POJ2777

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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值