P8936 月下缭乱 Sol

考虑对操作的区间 \([l_i,r_i]\) 的下标进行扫描线而不是对操作的值扫。用 \(m\)set 动态维护 \(x_i\) 对应的操作的下标集合,再用一个可删堆来维护当前所有操作 \(x_i\) 的最大值。这样的话 \(\text{sol}(l,r)=\text{sol}(1,m)\) 必须满足 \([l,r]\) 至少包含一个 \(x_i\) 为当前最大值的操作。

动态维护题目中要求的 \(f_i\),发现题目中要我们支持若干个形如 \(\forall i\in [l,r],f_i\leftarrow \max(f_i,r)\) 的操作,满足 \(x_r\) 为当前最大值或者 \(m+1\)

每个时间点当前最大值的个数之和是 \(O(n^2)\) 的,但我们发现当你操作了一个 set 里的所有值后,后面再去操作这个 set 剔除掉跟之前重复的操作,只需要操作这个 set 新删去的点现在的前驱后继即可。也就是说,本质不同的对 \(f_i\) 的区间取 max 操作在 \(O(n)\) 级别。

注意到对 \(f_i\) 的区间取 max 反正可以离线,干脆用扫描线+可删堆减少常数。

复杂度是 \(O(n\log n)\),空间复杂度 \(O(n)\)

然后你发现在出题人的精心策划下 \(O(n)\)set 被卡的又 M 又 T。

去掉所有的 vector,换用 \(O(n)\) 个树状树组维护前驱后继才卡过去。

#include <bits/stdc++.h>
using namespace std;
int read(){
	char c=getchar();int x=0;
	while(c<48||c>57) c=getchar();
	do x=(x<<1)+(x<<3)+(c^48),c=getchar();
	while(c>=48&&c<=57);
	return x;
}
typedef unsigned int ui;
typedef pair<int,int> pii;
const int N=1000003;
int n,m,rk;
int a[N],id[N],len[N],sz[N],lg[N];
pii sins[N],sdel[N],ains[N];
priority_queue<int> que;
int *del[N],base[N],cnt[N];
int *tr[N],trbase[N];
int *od[N],odbase[N];
bitset<N> add;
void upd(int p,int x,int v){
	sz[p]+=v;
	for(int i=id[x];i<=len[p];i+=(i&-i)) tr[p][i-1]+=v;
}
int qry(int p,int x){
	int res=0;
	for(int i=id[x];i;i^=(i&-i)) res+=tr[p][i-1];
	return res;
}
int loc(int p,int v){
	int x=0;
	for(int i=(1<<lg[len[p]]);i;i>>=1)
		if(x+i<=len[p]&&tr[p][x+i-1]<v) v-=tr[p][(x+=i)-1];
	return od[p][x];
}
int main(){
	n=read();m=read();
	for(int i=1;i<=m;++i){
		sins[i]=pii(read(),i);
		sdel[i]=pii(read()+1,i);
		id[i]=++len[a[i]=read()];
	}
	del[1]=base;tr[1]=trbase;od[1]=odbase;lg[0]=-1;
	for(int i=1;i<m;++i){
		del[i+1]=del[i]+len[i];
		tr[i+1]=tr[i]+len[i];
		od[i+1]=od[i]+len[i];
	}
	for(int i=1;i<=m;++i) od[a[i]][id[i]-1]=i,lg[i]=lg[i>>1]+1;
	int ix=1,dx=1;
	sort(sins+1,sins+m+1);
	sort(sdel+1,sdel+m+1);
	for(int i=1;i<=n;++i){
		while(ix<=m&&sins[ix].first<=i){
			int x=sins[ix++].second;
			if(!sz[a[x]]) que.emplace(a[x]);
			upd(a[x],x,1);
		}
		while(dx<=m&&sdel[dx].first<=i){
			int x=sdel[dx++].second;
			upd(a[x],x,-1);
			del[a[x]][cnt[a[x]]++]=x;
		}
		while(!que.empty()&&!sz[que.top()]) que.pop();
		if(que.empty()) continue;
		int mx=que.top();
		if(add[mx]){
			for(int t=0;t<cnt[mx];++t){
				int val=qry(mx,del[mx][t]);
				int rig=m+1,lef=0;
				if(val<sz[mx]) rig=loc(mx,val+1);
				if(val) lef=loc(mx,val);
				ains[++rk]=pii(lef+1,rig);
			}
		}
		else{
			int las=0;
			for(int i=1;i<=sz[mx];++i){
				int x=loc(mx,i);
				ains[++rk]=pii(las+1,x);
				las=x;
			}
			ains[++rk]=pii(las+1,m+1);add.set(mx);
		}
		cnt[mx]=0;
	}
	while(!que.empty()) que.pop();
	unsigned int fa=0,fb=0,fc=0;
	ix=1;sort(ains+1,ains+rk+1);
	for(int i=1;i<=m;++i){
		while(ix<=rk&&ains[ix].first<=i) que.emplace(ains[ix++].second);
		while(!que.empty()&&que.top()<=i) que.pop();
		int tmp=i;
		if(!que.empty()) tmp=que.top();
		unsigned int res=m+1-tmp;
		fa+=res;fb^=res*i;fc+=res*i;
	}
	printf("%u %u %u\n",fa,fb,fc);
	return 0;
}

posted @ 2023-02-03 22:19  yyyyxh  阅读(26)  评论(0编辑  收藏  举报