【题解】CF707D Persistent Bookcase

题目戳我

( ext{Solution:})

先考虑前三个操作,用(rev[i])表示第(i)行是不是被反转,(vis[i][j])表示点((i,j))是不是被反转。

(vis[i][j] ot=rev[i],)意味着(a[i][j]=0.)反之若(vis[i][j]=rev[i],)意味着(a[i][j]=1.)

解释:若(vis[i][j] ot=rev[i],)则说明这一行反转了而这个点没有再次反转,或者是这一行没有反转过而这一个点反转了,两者都表示(a[i][j]=1.)

后面同理。

考虑如何维护操作(4:)

考虑建立操作树,将操作之间连边,并将四操作之间的点连边。这意味这我们可以在执行到(k)操作的时候先处理有操作(4 o k)后面的操作。也就规避了所谓要持久化的要求。

同时观察到,若(x o y,)(forall iin [x+1,y-1],i ot o y.)因为一个点最多引出一条边。

于是复杂度和正确性得以保证。

#include<bits/stdc++.h>
using namespace std;
const int MAXN=3e5+10;
bool vis[10005][10005],rev[10005];
struct E{int nxt,to;}e[MAXN];
int tot,head[MAXN];
inline void add(int x,int y){e[++tot]=(E){head[x],y};head[x]=tot;}
int opt[MAXN],X[MAXN],Y[MAXN],s[MAXN],m,n,q;
typedef long long ll;
ll ans[MAXN];
void dfs(int x,int sum){
	int tmp=0,i=x;
	if(opt[i]==1){if(vis[X[i]][Y[i]]==rev[X[i]])tmp=1,++sum,++s[X[i]],vis[X[i]][Y[i]]=!rev[X[i]];}
	if(opt[i]==2){if(vis[X[i]][Y[i]]!=rev[X[i]])tmp=1,--sum,--s[X[i]],vis[X[i]][Y[i]]=rev[X[i]];}
	if(opt[i]==3){sum+=m-s[X[i]]-s[X[i]];rev[X[i]]^=1;s[X[i]]=m-s[X[i]];}
	ans[i]=sum;for(int i=head[x];i;i=e[i].nxt)dfs(e[i].to,sum);
	if(opt[x]==1&&tmp)--sum,--s[X[i]],vis[X[i]][Y[i]]=rev[X[i]];
	if(opt[x]==2&&tmp)++sum,++s[X[i]],vis[X[i]][Y[i]]=!rev[X[i]];
	if(opt[x]==3)sum-=m-s[X[i]]-s[X[i]],rev[X[i]]^=1,s[X[i]]=m-s[X[i]];
}
int main(){
	scanf("%d%d%d",&n,&m,&q);
	for(int i=1;i<=q;++i){
		scanf("%d%d",&opt[i],&X[i]);
		if(opt[i]<3)scanf("%d",&Y[i]);
		if(opt[i]==4)add(X[i],i);
		else add(i-1,i);
	}
	dfs(0,0);
	for(int i=1;i<=q;++i)printf("%lld
",ans[i]);
	return 0;
} 
原文地址:https://www.cnblogs.com/h-lka/p/13874933.html