首页 > 其他分享 >ABC372D ABC379F 题解 单调栈二分

ABC372D ABC379F 题解 单调栈二分

时间:2024-11-10 20:29:55浏览次数:1  
标签:二分 int 题解 ABC372D stk 序号 ABC379F id 单调

ABC372D ABC379F 题解 单调栈二分

一直觉得AT上面学到的东西比CF要多一些,无意捧一踩一,但可能是我太菜的原因,毕竟ABC的题目普遍要比Div.2 简单一些。

好多次碰到这个单调栈里面二分的 trick 了,所以写一篇来总结一下。

ABC 372 D

形象地给定一系列 Buildings 的高度 \(h\) ,保证每个 \(h\) 不相等。

问一共有多少对 \((i,j)\) 满足 \(i< j\) 并且其间不存在比 \(j\) 高的建筑。

我们考虑对于一个 \(j\) ,如果它之前存在一个比它高的建筑 \(j'\) ,那么对于所有 \(j'\) 之前的 \(i\) ,其都不能和 \(j\) 构成一个合法的对,那么这个 \(j\) 对于所有这样的 \(i\) 都是可以不用考虑的。

维护

那么这样的话我们其实就可以倒序枚举 \(i\) ,然后维护一个从顶到底单调递增的单调栈,被弹出的元素一定对现在以及之后所有的 \(i\) 不会有贡献了,所以可以直接弹出。

统计答案

每个答案实际上就是当前栈里的元素个数。

后话

貌似这个版本是不用再单调栈上面二分的,然而我当时如同一个 2b ,不仅使用了二分,甚至还用了差分和前缀和来统计每一个固定的 \(j\) 对 \(i\) 的贡献,而不是直接计算 \(i\) 的答案。

不过这也倒是间接为我在这个强化版问题上面提供了思路,导致想起来没有什么困难。

ABC 379 F

这个就是给定若干个 \((l_i,r_i)\) ,问在 \(r_i\) 的右边有多少建筑能够被 \(l_i\) 和 \(r_i\) 处的建筑同时看到。

分析

不难发现,满足答案的建筑所必须满足的必要条件是能够被 \(l_i\) 看到,当其序号满足在 \(r_i\) 右边的时候,这就变成了一个充要条件了。

所以我们直接离线,然后按左端点从小到大排序,然后倒序枚举区间,把所有 \(l_i\) 之后序号的放进单调栈里面,之后再二分找所有序号大于 \(r_i\) 的即可

维护

不难发现,我们即使不弹出,单调栈里面元素对应的序号也一定是单调的,所以单调栈里可以直接存序号,我们在维护的时候通过序号访问高度,在查询的时候直接查询序号即可。

Code

#include<bits/stdc++.h>
using namespace std;
template<typename T>inline void re(T &x)
{
	x=0;int f=1;char c=getchar();
	while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
	while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
	x*=f;
} 
template<typename T>inline void wr(T x)
{
	if(x>9)wr(x/10);
	putchar(x%10^48); 
}
inline void out(int x){wr(x),putchar('\n');}
const int N=2e5+10;
int stk[N],top;
struct seg
{
	int l,r,idx;
}a[N];
inline bool cmp(seg x,seg y)
{
	return x.l<y.l;
}
int ans[N]; 
int main()
{
	int n,q;
	cin>>n>>q;
	vector<int> h(n+1);
	for(int i=1;i<=n;++i)re(h[i]);
	for(int i=1;i<=q;++i)
		re(a[i].l),re(a[i].r),a[i].idx=i;
	sort(a+1,a+q+1,cmp);
	auto insert=[&](int x)
	{
		while(top&&h[x]>h[stk[top]])top--;
		stk[++top]=x;
	};
	auto bs=[&](int id)
	{
		if(id>=stk[1])return 0;
		int l=1,r=top;
		while(l<r)
		{
			int mid=(l+r+1)>>1;
			if(stk[mid]>id)l=mid;
			else r=mid-1;
		}
		return l;
	};
	int las=n;
	for(int i=q;i>=1;--i)
	{
		for(int id=las;id>a[i].l;--id)
			insert(id);
		las=a[i].l;	
		ans[a[i].idx]=bs(a[i].r);
//		printf("%d:%d\n",a[i].idx,bs(a[i].r));
	}
	for(int i=1;i<=q;++i)out(ans[i]);
	return 0;
}

标签:二分,int,题解,ABC372D,stk,序号,ABC379F,id,单调
From: https://www.cnblogs.com/Hanggoash/p/18538424

相关文章

  • P2123 皇后游戏 / [USACO12JAN] Mountain Climbing S / P1248 加工生产调度 题解
    P2123皇后游戏/[USACO12JAN]MountainClimbingS/P1248加工生产调度先来看P2123。我们把这个特别重要的公式打出来:\[c_{i}=\begin{cases}a_{1}+b_{1}&,i=1\\\displaystyle\max\left\{c_{i-1},\sum_{j=1}^{i}a_{j}\right\}+b_{i}&,2\leqi\leqn\end{......
  • 历年CSP-J初赛真题解析 | 2019年CSP-J初赛完善程序(34-43)
    学习C++从娃娃抓起!记录下CSP-J备考学习过程中的题目,记录每一个瞬间。附上汇总贴:历年CSP-J初赛真题解析|汇总_热爱编程的通信人的博客-CSDN博客矩阵变幻有一个奇幻的矩阵,在不停的变幻,其变幻方式为:数字0变成矩阵[......
  • [NOIP2012 提高组] 国王游戏 题解
    [NOIP2012提高组]国王游戏典贪心。设当前点为\(i\),\(\prod_{k=0}^{i-1}a_k\)为\(x\),则对于\(i,j\)两点的答案:(为了方便,记\(i+1=j\))\[\mathit{res}_1=\max\bigg(\dfracx{b_i},\dfrac{xa_i}{b_j}\bigg)~;\]若交换,则:\[\mathit{res}_2=\max\bigg(\dfracx{b_j},\dfrac{......
  • [luogu1248] 加工生产调度 题解
    考虑\(i\)排在\(j\)前的条件是\(a_i+\max(a_j,b_i)+b_j\lea_j+\max(a_i,b_j)+b_i\),然后发现这一坨东西是皇后游戏中的倒数第三个式子,直接转化为\(\min(a_j,b_i)\ge\min(a_i,b_j)\),然后就按皇后游戏中的排序方法就可以了……#include<bits/stdc++.h>#defineintlonglong......
  • [luogu1248] 加工生产调度 题解
    考虑\(i\)排在\(j\)前的条件是\(a_i+\max(a_j,b_i)+b_j\lea_j+\max(a_i,b_j)+b_i\),然后发现这一坨东西是皇后游戏中的倒数第三个式子,直接转化为\(\min(a_j,b_i)\ge\min(a_i,b_j)\),然后就按皇后游戏中的排序方法就可以了……#include<bits/stdc++.h>#defineintlonglong......
  • [luogu1248] 加工生产调度 题解
    考虑\(i\)排在\(j\)前的条件是\(a_i+\max(a_j,b_i)+b_j\lea_j+\max(a_i,b_j)+b_i\),然后发现这一坨东西是皇后游戏中的倒数第三个式子,直接转化为\(\min(a_j,b_i)\ge\min(a_i,b_j)\),然后就按皇后游戏中的排序方法就可以了……#include<bits/stdc++.h>#defineintlonglong......
  • CCPC 网络赛题解(D/I/J)
    D根据题目给出的构造方式,\(S_n'\)的长度会达到\(2^n\)数量级,没法求出\(S_n'\),所以考虑递推。设\(dp_{i,l,r}\)为\(S_i'\)里\(T\)的\([l,r]\)区间以子序列的方式出现了多少次,可以写出转移方程:\(dp_{i,l,r}=\sumdp_{i-1,l,k}\cdotdp_{i-1,k+1,r}+[a_i=T_k]\cdot......
  • [JXOI2017] 加法 题解
    最小值最大,考虑二分答案,问题转为判断最小值是否能\(\gex\)。假如\(a_i\gex\),那我们肯定不管;假如\(a_i<x\),那最好能让选择的区间\(r\)值更大,用优先队列维护即可。区间增幅可以用树状数组维护。时间复杂度\(O(n\log^2n)\)。#include<bits/stdc++.h>#defineintlonglon......
  • [CF1981E] Turtle and Intersected Segments 题解
    好题好题。难点在建图,因为图的边数将会决定最小生成树的时间复杂度。我们肯定希望能够只建\(O(n)\)级别的边,这样时间复杂度就可以做到\(O(n\logn)\)。观察到当\(i,j,k\)三个区间能够互相连边时(这里假设\(a_i<a_j<a_k\)),我们绝对不会连\((i,k)\)这条边。那么假如我们将......
  • [CF1981E] Turtle and Intersected Segments 题解
    好题好题。难点在建图,因为图的边数将会决定最小生成树的时间复杂度。我们肯定希望能够只建\(O(n)\)级别的边,这样时间复杂度就可以做到\(O(n\logn)\)。观察到当\(i,j,k\)三个区间能够互相连边时(这里假设\(a_i<a_j<a_k\)),我们绝对不会连\((i,k)\)这条边。那么假如我们将......