题目链接:http://codeforces.com/problemset/problem/707/D
有一个n*m的书架,有K个操作,求每个操作后一共有多少本书;有4种操作;
1:x y 如果 x y 位置没有书,放一本书在上面;
2:x y如果 x y 位置有书,移走;
3:x,表示把第x行的所有又书的拿走,没书的放上去;
4:k,回到第k个操作后的状态;
离线处理k个操作;当操作不为 4 时,把操作i连在i-1后,=4时把操作 i 连在a[i].x后;
这样建一棵树,然后遍历即可,在回溯的时候注意更改书架的状态即可;
#include<iostream> #include<algorithm> #include<string.h> #include<stdio.h> #include<math.h> #include<vector> using namespace std; #define N 1005 #define PI 4*atan(1.0) #define mod 1000000007 #define met(a, b) memset(a, b, sizeof(a)) typedef long long LL; struct node { int op, x, y, ans; }a[N*N];///k个操作; int cnt[N][N];///记录书架的状态; int n, m, k; vector<vector<int> > G;///操作形成的图; void dfs(int u) { if(a[u].op == 1) { int flag = 0; if(cnt[a[u].x][a[u].y] == 0) { flag = 1; a[u].ans ++;///在已有的基础上加上更改的值; cnt[a[u].x][a[u].y] = 1;///标记状态; } for(int i=0, len=G[u].size(); i<len; i++) { int v = G[u][i]; a[v].ans = a[u].ans;///往下走的时候,v是u的儿子,所以拥有u的ans; dfs(v); } if(flag)///回溯时要重新更改状态; cnt[a[u].x][a[u].y] = 0; } else if(a[u].op == 2) { int flag = 0; if(cnt[a[u].x][a[u].y] == 1) { flag = 1; a[u].ans --; cnt[a[u].x][a[u].y] = 0; } for(int i=0, len=G[u].size(); i<len; i++) { int v = G[u][i]; a[v].ans = a[u].ans; dfs(v); } if(flag) cnt[a[u].x][a[u].y] = 1; } else if(a[u].op == 3) { int num = 0; for(int i=1; i<=m; i++) { if(cnt[a[u].x][i] == 1) num ++; cnt[a[u].x][i] ^= 1; } a[u].ans = a[u].ans - num + (m-num);///更新ans; for(int i=0, len=G[u].size(); i<len; i++) { int v = G[u][i]; a[v].ans = a[u].ans; dfs(v); } for(int i=1; i<=m; i++) cnt[a[u].x][i] ^= 1; } else { for(int i=0, len=G[u].size(); i<len; i++) { int v = G[u][i]; a[v].ans = a[u].ans; dfs(v); } } } int main() { while(scanf("%d %d %d", &n, &m, &k)!=EOF) { met(a, 0); met(cnt, 0); G.clear(); G.resize(k+5); for(int i=1; i<=k; i++) { scanf("%d", &a[i].op); if(a[i].op <= 2) scanf("%d %d", &a[i].x, &a[i].y); else scanf("%d", &a[i].x); if(a[i].op <= 3) G[i-1].push_back(i); else G[a[i].x].push_back(i); } for(int i=0, len=G[0].size(); i<len; i++) dfs(G[0][i]); for(int i=1; i<=k; i++) printf("%d ", a[i].ans); } return 0; }