http://poj.org/problem?id=2777
这题的技巧是开一个储存颜色的变量col(longint类型,32位)来存储一段区间的颜色状态,从尾巴开始数第n位为1就表示有n颜色。比如:(49)10=(110,001)2,从尾巴开始数,第1、5、6位为1,所以表示该区间有第1、5、6种颜色。
接下来,染色过程color就要把区间染成设定的颜色,比如要染颜色6,则要把颜色值设为(100,000)2=(32)10,染颜色10,则要把颜色值设为(1,000,000,000)2=(512)10。颜色叠加用or(|)就好了。
最后是统计过程count,就用相应的颜色一个个判定有无就行了。比如查询(67)10有多少种颜色,则把67化为二进制1000011,然后分别用(1、10、100、…、1000000)2与(67)10做and(&)运算,若结果不为0,则tot++,最后返回tot即可。
链表+位运算做法
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
using namespace std;
#define maxn 100004
struct Node
{
int color;
int l, r;
Node *pleft, *pright;
bool end;
} tree[maxn * 3];
int n, t, o, ncount;
void buildtree(Node *proot, int l, int r)
{
proot->l = l;
proot->r = r;
proot->color = 1;
proot->end = true;
if (l == r)
return;
int mid = (l + r) / 2;
ncount++;
proot->pleft = tree + ncount;
ncount++;
proot->pright = tree + ncount;
buildtree(proot->pleft, l, mid);
buildtree(proot->pright, mid + 1, r);
}
void paint(Node *proot, int l, int r, int color)
{
if (proot->l == l && proot->r == r)
{
proot->end = true;
proot->color = color;
return;
}
if (proot->end)
{
proot->end = false;
proot->pleft->color = proot->color;
proot->pleft->end = true;
proot->pright->color = proot->color;
proot->pright->end = true;
}
int mid = (proot->l + proot->r) / 2;
if (r <= mid)
paint(proot->pleft, l, r, color);
else if(l > mid)
paint(proot->pright, l, r, color);
else
{
paint(proot->pleft, l, mid, color);
paint(proot->pright, mid +1, r, color);
}
proot->color = proot->pleft->color | proot->pright->color;
}
int query(Node *proot, int l, int r)
{
if (proot->end)
return proot->color;
if (proot->l == l && proot->r == r)
return proot->color;
int mid = (proot->l + proot->r) / 2;
if (r <= mid)
return query(proot->pleft, l, r);
else if(l > mid)
return query(proot->pright, l, r);
return query(proot->pleft, l, mid) | query(proot->pright, mid + 1, r);
}
int countbit(int a)
{
int x = 1;
int ret = 0;
for (int i = 0; i < 32; i++, x <<= 1)
if (x & a)
ret++;
return ret;
}
int main()
{
ncount = 0;
scanf("%d%d%d", &n, &t, &o);
getchar();
buildtree(tree, 1, n);
for (int i = 0; i < o; i++)
{
char order;
int l, r, c;
scanf("%c", &order);
if (order == 'C')
{
scanf("%d%d%d", &l, &r, &c);
if (l > r)
swap(l, r);
paint(tree, l, r, 1 << (c - 1));
}
else
{
scanf("%d%d", &l, &r);
if (l > r)
swap(l, r);
printf("%d\n", countbit(query(tree, l, r)));
}
getchar();
}
return 0;
}
标准做法
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int MAX=100000;
struct node
{
int left,right,cover;
};
node tree[MAX*3];
bool used[31];
void built(int L,int R,int id)//建树
{
tree[id].cover=1;//初始化颜色
tree[id].left=L;
tree[id].right=R;
if(L<R)
{
int mid=(L+R)/2;
built(L,mid,2*id); //左子树
built(mid+1,R,2*id+1); //右子树
}
}
void insert(int id,int L,int R,int col)
{
if(tree[id].left>=L&&tree[id].right<=R)
{
tree[id].cover=col;
return;
}
if(tree[id].left<tree[id].right)
{
int mid=(tree[id].left+tree[id].right)>>1;
if(tree[id].cover>0)
{
tree[id*2].cover=tree[id].cover;
tree[id*2+1].cover=tree[id].cover;
}
tree[id].cover=-1;
if(R<=mid)
insert(id*2,L,R,col);
else if(L>mid)
insert(id*2+1,L,R,col);
else
{
insert(id*2,L,mid,col);
insert(id*2+1,mid+1,R,col);
}
}
}
void cnt(int L,int R,int id)
{
if(tree[id].cover>0)
{
used[tree[id].cover]=true;
return;
}
if(tree[id].left<tree[id].right)
{
int mid=(tree[id].left+tree[id].right)>>1;
if(R<=mid)
cnt(L,R,id*2);
else if(L>mid)
cnt(L,R,id*2+1);
else
{
cnt(L,mid,id*2);
cnt(mid+1,R,id*2+1);
}
}
}
int main()
{
int L,T,Q;
scanf("%d %d %d",&L,&T,&Q);
int i,x,y,c;
built(1,L,1);
while(Q--)
{
char ch[2];
scanf("%s",ch);
if(ch[0]=='C')
{
scanf("%d %d %d",&x,&y,&c);
if(x<=y)
insert(1,x,y,c);
else
insert(1,y,x,c);
}
else
{
scanf("%d %d",&x,&y);
memset(used,false,sizeof(used));
if(x<=y)
cnt(x,y,1);
else
cnt(y,x,1);
int ans=0;
for(i=1;i<=T;i++)
if(used[i])ans++;
printf("%d\n",ans);
}
}
return 0;
}