Jzoj4838 I like Matrix!

(I DO NOT like matrix!!!)

首先我们可以暴力 O(nmq)

考虑压位(bitset)可以得到60pts

正解:我们发现,这些操作如果用边连接起来会形成一颗树(每个节点必然入度为1)

那我们考虑用离线方法,将所有的操作连接起来,dfs遍历整颗操作树,每个操作都暴力修改&还原

这样最多就是O(nq)的

然而我并不认为O(nq)能过,因为n<=1000 q<=100000,可能数据第一个操作比较多吧

#include<stdio.h>
#include<string.h>
#define N 100010
struct E{ int v,nt; } G[N];
int h[N],op[N][3],ans[N],n,m,q,c=0,S=0;
bool s[1010][1010];
inline void adj(int x,int y){ G[++c]=(E){y,h[x]}; h[x]=c; }
void mak(int x,int o,int i,int j){
	if(o==1){ S+=(s[i][j]?-1:1); s[i][j]^=1; }
	if(o==2){ for(j=1;j<=m;++j) S+=(s[i][j]?-1:1),s[i][j]^=1; }
	if(o==3){ for(j=1;j<=n;++j) S+=(s[j][i]?-1:1),s[j][i]^=1; }
}
void dijk(int x){
	if(x) mak(x,op[x][0],op[x][1],op[x][2]);
	if(x) ans[x]=S;
	for(int i=h[x];i;i=G[i].nt) dijk(G[i].v);
	if(x) mak(x,op[x][0],op[x][1],op[x][2]);
}
int main(){
	freopen("present.in","r",stdin);
	freopen("present.out","w",stdout);
	scanf("%d%d%d",&n,&m,&q);
	for(int x,y,i=1;i<=q;++i){
		scanf("%d%d",&x,&y);
		if(x==1){ x=y;
			scanf("%d",&y);
			op[i][0]=1;
			op[i][1]=x;
			op[i][2]=y;
			adj(i-1,i);
		} else if(x==2){
			op[i][0]=2;
			op[i][1]=y;
			adj(i-1,i);
		} else if(x==3){
			op[i][0]=3;
			op[i][1]=y;
			adj(i-1,i);
		} else { adj(y,i); }
	}
	dijk(0);
	for(int i=1;i<=q;++i) printf("%d\n",ans[i]);
}

posted @ 2017-10-30 21:46  扩展的灰(Extended_Ash)  阅读(88)  评论(0编辑  收藏  举报