题目链接:http://acm.hdu.edu.cn/viewcode.php?rid=32159923
题目大意:有n个矩形块,这些矩形块有R, G, B三种不同的颜色,最终区域的颜色由该区域上颜色的种类决定,要求输出 R, G, B, RG, RB, GB, RGB七种颜色的面积是多少。
思路:在前面区域覆盖面积的例题里,我们用一维数组维护被覆盖的区间长度,因为这里有颜色之分,所以可以再开一维表示颜色。此外,区域的颜色是由不同颜色的种类决定的,所以颜色的判断就可以很好地利用到或运算。
- (扫描线中为什么不用push_down)扫描线的例题中利用了线段树这种数据结构,但是我们每次查询的都是整体,没有去询问某个子区间,所以不用push_down。
AC1:
//cover[root][i]表示区间被第i种颜色覆盖的次数
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 0x3f3f3f3f
#define mid ((l + r)>>1)
#define chl root<<1
#define chr root<<1|1
using namespace std;
typedef unsigned long long ull;
typedef long long LL;
const int manx=2e4+10;
int sum[manx<<3][8],cover[manx<<3][3],X[manx<<1],n;
struct node
{
int y,lx,rx,color;
int val;
friend bool operator<(node a,node b)
{
return a.y<b.y;
}
}line[manx<<1];
void init()
{
memset(sum,0,sizeof(sum));
memset(cover,0,sizeof(cover));
}
void eval(int root,int l,int r)
{
int white=X[r+1]-X[l],Color=0;
for(int i=0; i<=2; i++)
if(cover[root][i])
Color|=(1<<i);
for(int i=1; i<=7; i++)
sum[root][i]=0;
for(int i=1; i<=7; i++)
{
sum[root][i|Color]+=sum[chl][i]+sum[chr][i];
white-=sum[chl][i]+sum[chr][i];
}
if(Color)
sum[root][Color]+=white;
}
void change(int root,int l,int r,int ll,int rr,int color,int val)
{
if(l==ll&&r==rr)
{
cover[root][color]+=val;
eval(root,l,r);
return;
}
if(rr<=mid)
change(chl,l,mid,ll,rr,color,val);
else if(ll>mid)
change(chr,mid+1,r,ll,rr,color,val);
else
{
change(chl,l,mid,ll,mid,color,val);
change(chr,mid+1,r,mid+1,rr,color,val);
}
eval(root,l,r);
}
int main()
{
int t,x1,y1,x2,y2,Cas=0;;
char str[2];
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
init();
for(int i=1; i<=n; i++)
{
int color;
scanf("%s%d%d%d%d",str,&x1,&y1,&x2,&y2);
if(str[0]=='R')
color=2;
else if(str[0]=='G')
color=1;
else
color=0;
line[2*i]=node{y1,x1,x2,color,1};
X[2*i]=x1;
line[2*i-1]=node{y2,x1,x2,color,-1};
X[2*i-1]=x2;
}
sort(line+1,line+2*n+1);
sort(X+1,X+2*n+1);
int cnt=unique(X+1,X+2*n+1)-X-1;
LL ans[8]= {0};
for(int i=1; i<2*n; i++)
{
int l=lower_bound(X+1,X+cnt+1,line[i].lx)-X;
int r=lower_bound(X+1,X+cnt+1,line[i].rx)-X-1;
int dy=line[i+1].y-line[i].y;
change(1,1,cnt,l,r,line[i].color,line[i].val);
for(int i=1; i<=7; i++)
ans[i]+=(LL)sum[1][i]*(LL)dy;
}
printf("Case %d:\n",++Cas);
printf("%lld\n%lld\n%lld\n%lld\n%lld\n%lld\n%lld\n",ans[4],ans[2],ans[1],ans[6],ans[5],ans[3],ans[7]);
}
return 0;
}
AC2:
记录一下当时找bug时的心情。。真的MLE到哭泣。
本来觉得找到了扫描线的快乐,后面把sum的第二维降到了7(sum[][7]),然后又试了下vector存数据,结果都超内存了,重要的是后面发现又是一个沙雕错误:把lower_bound里面的cnt写成了2*n
后面找博客还发现自己之前的思路有些复杂:cover可以只用记录三种颜色出现的次数,回溯更新覆盖区间长度时 再判断最终的颜色,这样cover的操作会简单很很很多
//cover[root][i]=1表示区间被i种颜色覆盖
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 0x3f3f3f3f
#define mid ((l + r)>>1)
#define chl root<<1
#define chr root<<1|1
using namespace std;
typedef unsigned long long ull;
typedef long long LL;
const int manx=2e4+10;
int sum[manx<<3][8],cover[manx<<3][8],X[manx<<1],n;
struct node
{
int y,lx,rx,color;
int val;
friend bool operator<(node a,node b)
{
return a.y<b.y;
}
}line[manx<<1];
void init()
{
memset(sum,0,sizeof(sum));
memset(cover,0,sizeof(cover));
//for(int i=1; i<=(n<<4); i++)
// cover[i][0]=1;
}
void eval(int root,int l,int r)
{
int white=X[r+1]-X[l],Color=0;
for(int i=1; i<=7; i++)
if(cover[root][i])
{
Color=max(Color,i);
}
for(int i=1; i<=7; i++)
sum[root][i]=0;
for(int i=1; i<=7; i++)
{
sum[root][i|Color]+=sum[chl][i]+sum[chr][i];
white-=sum[chl][i]+sum[chr][i];
}
if(Color)
sum[root][Color]+=white;
}
void change(int root,int l,int r,int ll,int rr,int color,int val)
{
if(l==ll&&r==rr)
{
if(val==1)
{
int flag=0;
for(int i=1; i<=7; i++)
if(cover[root][i])
{
flag=max(flag,i);
}
cover[root][(1<<color)]++;
if(flag&&flag!=(1<<color))
cover[root][flag|(1<<color)]=1;
}
else
{
cover[root][(1<<color)]--;
if(!cover[root][(1<<color)])
for(int i=1; i<=7; i++)
if((i&(1<<color))&&cover[root][i])//需要color色
{
cover[root][i]=0;
int temp=i-(1<<color);
if(temp!=1&&temp!=2&&temp!=4)
cover[root][temp]=1;
}
}
eval(root,l,r);
return;
}
if(rr<=mid)
change(chl,l,mid,ll,rr,color,val);
else if(ll>mid)
change(chr,mid+1,r,ll,rr,color,val);
else
{
change(chl,l,mid,ll,mid,color,val);
change(chr,mid+1,r,mid+1,rr,color,val);
}
eval(root,l,r);
}
int main()
{
int t,x1,y1,x2,y2,Cas=0;;
char str[2];
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
init();
for(int i=1; i<=n; i++)
{
int color;
scanf("%s%d%d%d%d",str,&x1,&y1,&x2,&y2);
if(str[0]=='R')
color=2;
else if(str[0]=='G')
color=1;
else
color=0;
line[2*i]=node{y1,x1,x2,color,1};
X[2*i]=x1;
line[2*i-1]=node{y2,x1,x2,color,-1};
X[2*i-1]=x2;
}
sort(line+1,line+2*n+1);
sort(X+1,X+2*n+1);
int cnt=unique(X+1,X+2*n+1)-X-1;
LL ans[8]= {0};
for(int i=1; i<2*n; i++)
{
int l=lower_bound(X+1,X+cnt+1,line[i].lx)-X;
int r=lower_bound(X+1,X+cnt+1,line[i].rx)-X-1;
int dy=line[i+1].y-line[i].y;
change(1,1,cnt,l,r,line[i].color,line[i].val);
for(int i=1; i<=7; i++)
ans[i]+=(LL)sum[1][i]*(LL)dy;
}
printf("Case %d:\n",++Cas);
printf("%lld\n%lld\n%lld\n%lld\n%lld\n%lld\n%lld\n",ans[4],ans[2],ans[1],ans[6],ans[5],ans[3],ans[7]);
}
return 0;
}
来源:CSDN
作者:小鱼yn
链接:https://blog.csdn.net/qq_43803508/article/details/104006724