「NOI Online 2022 提高组」丹钓战 [题解]

chenyining 2024-01-07 11:32:09 2024-01-14 8:47:28 8 返回题目

显然,一个二元组是不是 “成功的” 只与前面的二元组有关,和后面的二元组无关,所以我们可以预处理出每个二元组被看做 “成功的” 最小左端点,即 的含义为二元组 弹栈一直到 就不是 “成功的” 了,这部分可以用栈解决。(注:对于枚举完还没有被处理到的,显然它的 ,还要处理一遍)。

那这个预处理有什么用呢?显然,一个区间 的答案就是 里小于 的数量就是答案,可是这样复杂度就为 了,那我们怎么办?可以用离线 树状数组解决。对于每个左端点,提前减掉小于 的重复部分,对于每个右端点,就将答案加上所有小于 的数量,这样就是正确答案。

部分代码:


int lowbit(int x){return x&(-x);}
void add(int x,int v){for(int i=x;i<=n;i+=lowbit(i))s[i]+=v;}
int gts(int x){
	int sum=0;
	for(int i=x;i;i-=lowbit(i))
		sum+=s[i];
	return sum;
}
signed main(){
	for(int i=n;i>=1;i--){//逆序
		while(top&&aa[stk[top]]!=aa[i]&&bb[stk[top]]<bb[i])last[stk[top--]]=i+1;//找最小左端点
		stk[++top]=i;
	}
	while(top)last[stk[top--]]=1;	//剩下的都为1
	for(int i=1;i<=n;i++){
		for(int j=0;j<al[i].size();j++)ans[al[i][j]]-=gts(...);add(last[i],1);
		for(int j=0;j<br[i].size();j++)ans[br[i][j]]+=gts(...);
	}
	return 0;
}
{{ vote && vote.total.up }}