Always keep a b|

luckydrawbox

园龄:4个月粉丝:1关注:2

P8251 [NOI Online 2022 提高组] 丹钓战

Link\text{Link}

题意

nn 个二元组 (ai,bi)(a_i, b_i),编号为 11nn

有一个初始为空的栈 SS,向其中加入元素 (ai,bi)(a_i, b_i) 时,先不断弹出栈顶元素直至栈空或栈顶元素 (aj,bj)(a_j , b_j) 满足 aiaja_i \neq a_jbi<bjb_i < b_j,然后再将其加入栈中。

如果一个二元组入栈后栈内只有这一个元素,则称该二元组是“成功的”。

qq 个询问 [l,r][l, r],表示若将编号在 [l,r][l, r] 中的二元组按编号从小到大依次入栈,会有多少个二元组是“成功的”。

询问之间相互独立。

分析

仔细观察可以发现,在加入元素 (ai,bi)(a_i, b_i) 前,弹出元素后,要么栈变空了,要么会出现一个满足 ai=acia_i = a_{c_i}bi>bcib_i > b_{c_i} 的元素 (aci,bci)(a_{c_i}, b_{c_i}) 阻止弹出,又因为加入操作的顺序是固定从左到右的,所以 cic_i 是固定的一个数(如果 cic_i 不存在则设为 00)。

所以在一组询问 [l,r][l,r] 中,二元组 (ai,bi)(lir)(a_i, b_i)(l\le i\le r) 是成功的仅当 cic_i 不在 [l,r][l,r] 中,即 ci<lc_i<l

那么,问题就转化成了求 ci<l(lir)c_i<l(l\le i\le r) 的个数。

于是大致流程就出来了。

首先把询问读入,要进行离线处理,再根据题意模拟一遍,求出所有的 cic_i,同时把 cic_i 放进树状数组,求出 cic_i 的个数的前缀和 suml1,sumrsum_{l-1},sum_r,二者的差就是答案。

代码

时间复杂度 O((n+q)logn)O((n+q)\log n)

#include<bits/stdc++.h>
#define ll long long
using namespace std;
long long read(){
	long long x=0,f=1;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}
	while(isdigit(ch)){x=x*10+ch-48;ch=getchar();}
	return x*f;
}
void write(long long x){
    if(x<0) putchar('-'),x=-x;
    if(x>9) write(x/10);
    putchar(x%10+'0');
}
const int N=5e5+10;
int n,q,a[N],b[N],z[N],t,ans;
struct Q{
	int l,r,ans;
}d[N];
int headl[N],nxtl[N*2],verl[N*2],totl;
void addl(int x,int y){
	verl[++totl]=y;
	nxtl[totl]=headl[x];
	headl[x]=totl;
}
int headr[N],nxtr[N*2],verr[N*2],totr;
void addr(int x,int y){
	verr[++totr]=y;
	nxtr[totr]=headr[x];
	headr[x]=totr;
}
vector<int>el[N],er[N];
int f[N];
void add(int x,int v){
	x++;
	for(;x<=n;x+=x&-x)
		f[x]+=v;
}
int ask(int x){
	x++;
	int ans=0;
	for(;x;x-=x&-x)
		ans+=f[x];
	return ans;
}
int main(){
	//freopen("stack.in","r",stdin);
	//freopen("stack.out","w",stdout);
	n=read();q=read();
	for(int i=1;i<=n;i++)
		a[i]=read();
	for(int i=1;i<=n;i++)
		b[i]=read();
	for(int i=1;i<=q;i++){
		d[i].l=read();
		d[i].r=read();
		addl(d[i].l-1,i);
		addr(d[i].r,i);
	}
	for(int i=1;i<=n;i++){
		while(t&&(a[z[t]]==a[i]||b[z[t]]<=b[i]))
			t--;
		add(z[t],1);
		z[++t]=i;
		for(int j=headl[i];j;j=nxtl[j])
			d[verl[j]].ans-=ask(d[verl[j]].l-1);
		for(int j=headr[i];j;j=nxtr[j])
			d[verr[j]].ans+=ask(d[verr[j]].l-1);
	}
	for(int i=1;i<=q;i++){
		write(d[i].ans);
		puts("");
	}
	return 0;
}

本文作者:luckydrawbox

本文链接:https://www.cnblogs.com/luckydrawbox/p/18526540

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   luckydrawbox  阅读(1)  评论(0编辑  收藏  举报  
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起