一共四种操作:
①1 x y 如果位子(x,y)没有书,就在上边放一本书。
②2 x y 如果位子(x,y)有书,就拿走这本书。
③ 3 x 在第x行上,如果有书,就拿走,如果没有书 ,就放一本。
④4 x 回到第x次操作结束后的状态。
问每个操作结束后,书架上共有多少本书。
思路(源自:http://blog.csdn.net/miracle_ma/article/details/52290831,很妙的解法):
1、首先我们优化修改操作,我们可以将第三种操作也变成O(1);
我们过程维护一个row【x】,表示第x行有多少本书,那么对应第三种操作对于总数量的影响为:sum=sum-row【x】+m-row【x】;
同时,对于书架的第x行,我们进行了一次翻转,那么维护一个数组fan【x】,记录第x行是否翻转过。
那么过程维护这个sum和几个数组还是很简单的。
三种操作配合亦或,总查询复杂度O(1);
2、再考虑到Dfs的特点,我们考虑用Dfs的方式来搞这个题。
首先,对于每个修改操作,对应将i-1和i连边.
如果不是修改操作(op==4),对应将回到的位子和i连边。
接下来维护Dfs过程即可。
Ac代码:
#include<stdio.h>
#include<vector>
#include<string.h>
using namespace std;
struct node
{
int op,x,y;
}p[100050];
vector<int >mp[100005];
int a[1005][1005];
int fan[1005];
int row[1005];
int ans[100505];
int n,m,q,sum;
void Dfs(int pos)
{
int flag=0;
if(pos!=0)
{
if(p[pos].op==1)
{
if(a[p[pos].x][p[pos].y]^fan[p[pos].x]==0)
{
sum++;
a[p[pos].x][p[pos].y]^=1;
row[p[pos].x]++;
flag=1;
}
}
if(p[pos].op==2)
{
if(a[p[pos].x][p[pos].y]^fan[p[pos].x]==1)
{
sum--;
a[p[pos].x][p[pos].y]^=1;
row[p[pos].x]--;
flag=1;
}
}
if(p[pos].op==3)
{
sum-=row[p[pos].x];
sum+=m-row[p[pos].x];
fan[p[pos].x]^=1;
row[p[pos].x]=m-row[p[pos].x];
flag=1;
}
ans[pos]=sum;
}
for(int i=0;i<mp[pos].size();i++)
{
int v=mp[pos][i];
Dfs(v);
}
if(pos!=0&&flag==1)
{
if(p[pos].op==1)
{
sum--;
a[p[pos].x][p[pos].y]^=1;
row[p[pos].x]--;
}
if(p[pos].op==2)
{
sum++;
a[p[pos].x][p[pos].y]^=1;
row[p[pos].x]++;
flag=1;
}
if(p[pos].op==3)
{
sum-=row[p[pos].x];
sum+=m-row[p[pos].x];
fan[p[pos].x]^=1;
row[p[pos].x]=m-row[p[pos].x];
flag=1;
}
}
}
int main()
{
while(~scanf("%d%d%d",&n,&m,&q))
{
for(int i=1;i<=100003;i++)mp[i].clear();
for(int i=1;i<=q;i++)
{
scanf("%d",&p[i].op);
if(p[i].op==1||p[i].op==2)scanf("%d%d",&p[i].x,&p[i].y);
else scanf("%d",&p[i].x);
if(p[i].op==4)
{
mp[p[i].x].push_back(i);
}
else
{
mp[i-1].push_back(i);
}
}
sum=0;
memset(a,0,sizeof(a));
memset(fan,0,sizeof(fan));
memset(row,0,sizeof(row));
memset(ans,0,sizeof(ans));
Dfs(0);
for(int i=1;i<=q;i++)
{
printf("%d\n",ans[i]);
}
}
}