題目鏈接: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;
}