Codeforces Round #368 (Div. 2) D &E

来源:互联网 发布:营口港荣数据大平台 编辑:程序博客网 时间:2024/04/29 17:30

题目链接: Codeforces Round #368 (Div. 2) D - Persistent Bookcase

题意:维护一个布尔矩阵s,支持四种操作:

(1) 1,x,y   将s[x][y]赋值为true(放书)

(2) 2,x,y   将s[x][y]赋值为false(取书)

(3) 3,x      将第x行所有值翻转(true->false,false->true)

(4)4,x       回到第x次操作后的情况

每次操作之后输出值为true的个数。

分析:

容易发现,操作形成了一棵树的结构:

     (1)  如果第i个操作为1~3类,那么他的父亲是i-1.

     (2) 如果是第4类,他父亲为x。

 当时想到了这一点,但是并没有想到直接深搜能过(F**k!)。

主意正常的还原现场即可,居然一写就过。

代码如下:

#include<cstdio>#include<iostream>#include<cstdlib>#include<cmath>#include<cstring>#include<queue>#include<vector>#include<algorithm>#define LL long long#define CLEAR(xxx) memset(xxx,0,sizeof(xxx))using namespace std;const int maxn=2000+5,maxq=100000+5;int n,m,q,tot,line[maxn],ans[maxq];   //line表示每行有多少书 int e,last[maxq],Next[maxq],to[maxq];bool book[maxn][maxn];  //标记有没有书 struct query{int id,p,x,y;}ask[maxq];inline void _read(int &x){char ch=getchar(); bool mark=false;for(;!isdigit(ch);ch=getchar())if(ch=='-')mark=true;for(x=0;isdigit(ch);ch=getchar())x=x*10+ch-'0';if(mark)x=-x;}void Addedge(int x,int y){to[++e]=y;Next[e]=last[x];last[x]=e;}void DFS(int x){int i;bool flag=false;  //flag=true表示当前操作有效 query& q=ask[x];if(q.p==1&&!book[q.x][q.y]){tot++; flag=true;book[q.x][q.y]=true;line[q.x]++;}else if(q.p==2&&book[q.x][q.y]){tot--; flag=true;book[q.x][q.y]=false;line[q.x]--;}else if(q.p==3){flag=true;tot+=m-2*line[q.x];line[q.x]=m-line[q.x];for(i=1;i<=m;i++)book[q.x][i]=!book[q.x][i];}ans[q.id]=tot;for(i=last[x];i!=-1;i=Next[i])DFS(to[i]);if(!flag) return ;//还原现场 if(q.p==1){tot--; book[q.x][q.y]=false;line[q.x]--;}else if(q.p==2){tot++; book[q.x][q.y]=true;line[q.x]++;}else if(q.p==3){tot+=m-2*line[q.x];line[q.x]=m-line[q.x];for(i=1;i<=m;i++)book[q.x][i]=!book[q.x][i];}}int main(){int i,j,x,y,z;_read(n);_read(m);_read(q);memset(last,-1,sizeof(last));for(i=1;i<=q;i++){ask[i].id=i;_read(ask[i].p);if(ask[i].p!=4){Addedge(i-1,i);_read(ask[i].x);if(ask[i].p!=3) _read(ask[i].y);}else {_read(x);Addedge(x,i);}}DFS(0);for(i=1;i<=q;i++) printf("%d\n",ans[i]);return 0;}

E 题目链接: Codeforces Round #368 (Div. 2) E. Garlands

大意: 一个n*m矩阵中有若干个灯泡,组成k个块(逐个给出),每个灯泡有一定的欢乐值。

有以下两种操作:

(1) SWITCH  k 改变第K个块中所有灯泡的开情况(一开始全部为打开)。

(2) ASK x1,y1,x2,y2  询问左上(x1,y1),右下(x2,y2)这个矩形中,所有打开的灯泡的欢乐值之和。


分析:

由于ask操作不超过2000个,所以考虑离线操作:

将第i个块落在第j个询问的区域的灯泡的欢乐值之和预处理出来(cnt[i][j]),再记录下每个块的开关情况就好了。

答案就是所有打开的块cnt之和。

快速的修改矩阵中的元素,并查询前缀和,用二维树状数组来维护。

代码如下:

#include<cstdio>#include<iostream>#include<cstring>#include<queue>#include<vector>#include<algorithm>#define LL long long#define CLEAR(xxx) memset(xxx,0,sizeof(xxx))using namespace std;const int maxn=2000+5,maxq=1000000+5;int n,m,k,q,flip[maxq];int x1[maxq],x2[maxq],y1[maxq],y2[maxq];  //存的是询问 LL c[maxn][maxn],cnt[maxn][maxn];int is_on[maxn]; // cnt[i][j]表示第i个连通块在第j个询问范围内的欢乐值总和 struct grid{int x,y; LL w;grid(int x,int y,int w):x(x),y(y),w((LL)w){}};vector<grid> group[maxn];  //记录每个块 inline void _read(int &x){char ch=getchar(); bool mark=false;for(;!isdigit(ch);ch=getchar())if(ch=='-')mark=true;for(x=0;isdigit(ch);ch=getchar())x=x*10+ch-'0';if(mark)x=-x;}inline int lowbit(int x){return x&-x;}inline void Add(int x,int y,LL d){for(int i=x;i<=maxn;i+=lowbit(i))    //注意,这里一定要写maxn!!n会wa得很惨 for(int j=y;j<=maxn;j+=lowbit(j))c[i][j]+=d;}inline LL Sum(int x,int y){LL ans=0;for(int i=x;i>0;i-=lowbit(i))for(int j=y;j>0;j-=lowbit(j))ans+=c[i][j];return ans;} int main(){int i,j,len,xx,yy,ww,zz;_read(n);_read(m);_read(k);for(i=1;i<=k;i++){_read(zz);for(j=0;j<zz;j++){_read(xx); _read(yy); _read(ww);group[i].push_back(grid(xx,yy,ww));}}char str[10];int ask=0;_read(q);for(i=1;i<=q;i++){scanf("%s",str);if(str[0]=='S')_read(flip[i]);else {ask++;_read(x1[ask]); _read(y1[ask]);_read(x2[ask]); _read(y2[ask]);}}for(i=1;i<=k;i++){   //预处理cnt数组 for(j=0;j<group[i].size();j++)Add(group[i][j].y,group[i][j].x,group[i][j].w);for(j=1;j<=ask;j++)  //一个标准的二维前缀和 cnt[i][j]=Sum(y2[j],x2[j])+Sum(y1[j]-1,x1[j]-1)-Sum(y1[j]-1,x2[j])-Sum(y2[j],x1[j]-1);for(j=0;j<group[i].size();j++)Add(group[i][j].y,group[i][j].x,-group[i][j].w);}for(i=1;i<=k;i++)is_on[i]=1;   //最初全部打开 int cur=0;for(i=1;i<=q;i++){LL ans=0;if(flip[i])is_on[flip[i]]^=1;    //取反 else {cur++;for(j=1;j<=k;j++)if(is_on[j]) ans+=cnt[j][cur];   cout<<ans<<endl;}}return 0;}

#include<iostream>#include<cstdio>#include<algorithm>#include<cstdlib>#include<vector>#include<cstring>using namespace std;inline void _read(long long &x){      char ch=getchar(); bool mark=false;      for(;!isdigit(ch);ch=getchar())if(ch=='-')mark=true;      for(x=0;isdigit(ch);ch=getchar())x=x*10+ch-'0';      if(mark)x=-x;  }  const long long maxn=2005;long long n,m,k,q;struct node{long long x,y,w; node(){}node(long long a,long long b,long long c){x=a;y=b;w=c;}};vector<node> a[maxn];long long work[1000005];long long c[maxn][maxn];long long cnt[maxn][maxn];bool on[maxn];long long lowbit(long long x){return x&(-x);}void modify(long long x,long long y,long long d){for(long long i=x;i<=maxn;i+=lowbit(i)){for(long long j=y;j<=maxn;j+=lowbit(j)){c[i][j]+=d;}}}long long getsum(long long x,long long y){long long sum=0;for(long long i=x;i;i-=lowbit(i)){for(long long j=y;j;j-=lowbit(j)){sum+=c[i][j];}}return sum;}long long tot=0;struct node2{long long x1,y1,x2,y2;};node2 ask[1000005];int main(){long long i,j;cin>>n>>m>>k;for(i=1;i<=k;i++){long long len;_read(len);for(j=1;j<=len;j++){long long x,y,w;_read(x);_read(y);_read(w);a[i].push_back(node(x,y,w));}}cin>>q;for(i=1;i<=q;i++){char s[10];scanf("%s",s);if(s[0]=='S'){_read(work[i]);}else{tot++;_read(ask[tot].x1);_read(ask[tot].y1);_read(ask[tot].x2);_read(ask[tot].y2);}}for(i=1;i<=k;i++){for(j=0;j<a[i].size();j++){modify(a[i][j].x,a[i][j].y,a[i][j].w);}for(j=1;j<=tot;j++){cnt[i][j]=getsum(ask[j].x2,ask[j].y2)+getsum(ask[j].x1-1,ask[j].y1-1)-getsum(ask[j].x2,ask[j].y1-1)-getsum(ask[j].x1-1,ask[j].y2);}for(j=0;j<a[i].size();j++){modify(a[i][j].x,a[i][j].y,-a[i][j].w);}}for(i=1;i<=k;i++)on[i]=true;long long l=0;for(i=1;i<=q;i++){if(work[i]){on[work[i]]=(!on[work[i]]);}else{long long ans=0;l++;for(j=1;j<=k;j++){if(on[j])ans+=cnt[j][l];}printf("%I64d\n",ans);}}}


0 0