poj2777

本题是典型的线段树的题目,由于颜色的数目较少,所以只使用一个整形变量来表示。

 

#include<iostream>

using namespace std;

 

struct node//结构

{

int l,r;//左右子树

int col;//颜色

}a[1000000];

int L,T,O;

int cnt;

 

inline bool single(int a) //判断是否只有一种颜色

{

return (((a-1)&a)==0);

}

 

void insert(int l,int r,int c,int p) //更新

{

if(l<=a[p].l&&r>=a[p].r)//如果当前子树在lr区间内,那么所有子区间都是颜色C

{

a[p].col=c;

return;

}

if(a[p].col==c)//如果当前节点子树区间的颜色和要染色相同,那么直接返回,这个是个优化

{

return;

}

if (single(a[p].col)) //如果是单色,子区间也是单色

{

a[2*p].col=a[p].col;

a[2*p+1].col=a[p].col;

}

int mid=(a[p].l+a[p].r)>>1;

if(l<=mid) 

insert(l,r,c,2*p);

if(r>mid) 

insert(l,r,c,2*p+1);

a[p].col=a[2*p].col|a[2*p+1].col;

}

 

 

void search(int l,int r,int p,int &cnt)//查询

{

if(l<=a[p].l&&r>=a[p].r)

{

cnt|=a[p].col;

return;

}

if(single(a[p].col))

{

cnt|=a[p].col;

return;

}

int mid=(a[p].l+a[p].r)>>1;

if(l<=mid)

search(l,r,2*p,cnt);

if(r>mid)

search(l,r,2*p+1,cnt);

}

 

void construct(int l,int r,int p)

{

if(l==r)

{

a[p].l=a[p].r=l;

return;

}

a[p].l=l;

a[p].r=r;

int mid=(l+r)>>1;

construct(l,mid,2*p);

construct(mid+1,r,2*p+1);

}

 

int cal(int p)

{

int num=0;

while(p)

{

if(p%2)

num++;

p>>=1;

}

return num;

}

 

int main()

{

scanf("%d%d%d",&L,&T,&O);

construct(1,L,1);

insert(1,L,1,1);

int st,en,col;

char ch;

while(O--)

{

getchar();

scanf("%c",&ch);

if(ch=='C')

{

scanf("%d%d%d",&st,&en,&col);

if(st>en)

{

int tmp=st;st=en;en=tmp;

}

insert(st,en,1<<(col-1),1);

}

else

{

scanf("%d%d",&st,&en);

if(st>en)

{

int tmp=st;st=en;en=tmp;

}

cnt=0;

search(st,en,1,cnt);

printf("%d/n",cal(cnt)); 

}

}

return 0;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值