题目大意:给一个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