题目请戳这里
题目大意:给一个n*m的矩形,有9中颜色,4种集合图形,q个操作,每个操作是将矩形中指定位置的某种几何形状的格子染相应的颜色。求最后9种颜色相应的数量。
题目分析:第一眼感觉就是线段树,一开始想的是写个二维的线段树,然后就在想怎么更新比较快。发现二维线段树除了更新矩形外对于其他3个图形的更新毫无优势。如果一行一行的更新,太慢了。一直在纠结怎样快速成段更新其他3种几何图像。最后1个小时决定敲一下,敲了一会也放弃了。还好没有继续敲。
这题官方题解给的是O(n*m)的线性做法。不过线段树也是可以做的。只是要写n棵线段树,而不是二维的!!其实写n棵线段树也容易爆内存的,何况二维的。再考虑到每次对一个格子涂色后就会覆盖上一次的颜色,所以每个格子最终的颜色取决于最后一次涂的颜色。所以要把查询倒着做!!涂过颜色的格子就删掉。这样线段树就比较容易完成了。不过效率并不是十分高,踩线过。。
唉,2道线段树,一道都没出,到现在了,还是这么弱啊。。。
详情请见代码:
#include <iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> using namespace std; const int N = 201; const int M = 50001; struct nd { char c; int p[5]; }ask[M]; int m,n,q; int ans[11]; struct segt { short int tree[M<<2]; void init(int num,int s,int e) { if(s == e) { tree[num] = 1; return; } int mid = (s + e)>>1; init(num<<1,s,mid); init(num<<1|1,mid + 1,e); tree[num] = tree[num<<1] + tree[num<<1|1]; } int query(int num,int s,int e,int l,int r) { if(s == l && e == r) return tree[num]; if(tree[num] == 0) return 0; int mid = (s + e)>>1; if(r <= mid) return query(num<<1,s,mid,l,r); else { if(l > mid) return query(num<<1|1,mid + 1,e,l,r); else return query(num<<1,s,mid,l,mid) + query(num<<1|1,mid + 1,e,mid + 1,r); } } void insert(int num,int s,int e,int l,int r) { if(s == l && e == r) { tree[num] = 0; return; } if(tree[num] == 0) return; int mid = (s + e)>>1; if(r <= mid) insert(num<<1,s,mid,l,r); else { if(l > mid) insert(num<<1|1,mid + 1,e,l,r); else { insert(num<<1,s,mid,l,mid); insert(num<<1|1,mid + 1,e,mid + 1,r); } } tree[num] = tree[num<<1] + tree[num<<1|1]; } }lcm[N]; void Circle(int id) { int i,l,r; for(i = ask[id].p[0] + 1 - ask[id].p[2];i <= ask[id].p[0] + 1 + ask[id].p[2];i ++) { if(i < 1) continue; if(i > n) break; int tmp = (int)sqrt((double)(ask[id].p[2] * ask[id].p[2] - (i - ask[id].p[0] - 1) * (i - ask[id].p[0] - 1))); l = ask[id].p[1] + 1 - tmp; r = ask[id].p[1] + 1 + tmp; if(l < 1) l = 1; if(r > m) r = m; if(l > r) continue; tmp = lcm[i].query(1,1,m,l,r); if(tmp) { ans[ask[id].p[3]] += tmp; lcm[i].insert(1,1,m,l,r); } } } void Diamond(int id) { int i,l,r; for(i = ask[id].p[0] + 1 - ask[id].p[2];i <= ask[id].p[0] + 1 + ask[id].p[2];i ++) { if(i < 1) continue; if(i > n) break; l = ask[id].p[1] + 1 - ask[id].p[2] + abs(i - ask[id].p[0] - 1); r = ask[id].p[1] + 1 + ask[id].p[2] - abs(i - ask[id].p[0] - 1); if(l < 1) l = 1; if(r > m) r = m; if(l > r) continue; int tmp = lcm[i].query(1,1,m,l,r); if(tmp) { ans[ask[id].p[3]] += tmp; lcm[i].insert(1,1,m,l,r); } } } void Triangle(int id) { int i,l,r; int h = (ask[id].p[2] + 1)>>1; int cnt = 0; for(i = ask[id].p[0] + h;i >= ask[id].p[0] + 1;i --,cnt ++) { if(i > n) continue; l = ask[id].p[1] + 1 - cnt; r = ask[id].p[1] + 1 + cnt; if(l < 1) l = 1; if(r > m) r = m; int tmp = lcm[i].query(1,1,m,l,r); if(tmp) { ans[ask[id].p[3]] += tmp; lcm[i].insert(1,1,m,l,r); } } } void Rectangle(int id) { int i,l,r; l = ask[id].p[1] + 1; r = ask[id].p[1] + ask[id].p[3]; if(l > r) return; if(r > m) r = m; for(i = ask[id].p[0] + 1;i <= ask[id].p[0] + ask[id].p[2];i ++) { if(i > n) break; int tmp = lcm[i].query(1,1,m,l,r); if(tmp) { ans[ask[id].p[4]] += tmp; lcm[i].insert(1,1,m,l,r); } } } char op[12]; int main() { int i; while(scanf("%d",&n) != EOF) { scanf("%d%d",&m,&q); for(i = 1;i <= n;i ++) lcm[i].init(1,1,m); memset(ans,0,sizeof(ans)); for(i = 1;i <= q;i ++) { scanf("%s",op); ask[i].c = op[0]; for(int j = 0;j < 4;j ++) scanf("%d",&ask[i].p[j]); if(*op == 'R') scanf("%d",&ask[i].p[4]); } for(i = q;i >= 1;i --) { switch(ask[i].c) { case 'C':Circle(i);break; case 'D':Diamond(i);break; case 'T':Triangle(i);break; case 'R':Rectangle(i);break; } } for(i = 1;i < 9;i ++) printf("%d ",ans[i]); printf("%d\n",ans[i]); } return 0; } //4484MS 53624K