1. 程式人生 > >線段樹+狀壓 色板遊戲

線段樹+狀壓 色板遊戲

題意:一個色板,一開始全為 1 1 號顏色,有兩種操作:第一種是將區間 A B A-B 全部變為 C

C 號顏色,第二種是詢問區間 A B A-B 一共有多少種顏色。顏色數量 < =
30 <=30

考慮將每一種顏色進行狀壓, t r [   ] .

s u m tr[\ ].sum 即表示這個區間的顏色狀壓後的值,每次更新使用 | 更新 s u m sum ,修改就是區間覆蓋, p u s h d o w n pushdown 也直接覆蓋即可。

#include<bits/stdc++.h>
using namespace std;
struct node
{
	int l,r;
	int sum,tag;
}tr[404000];
int l,t,o;
void build(int rt,int l,int r)
{
	tr[rt].l=l;
	tr[rt].r=r;
	if(l==r)
	{
		tr[rt].sum=1;
		return;
	}
	int mid=(l+r)/2;
	build(rt*2,l,mid);
	build(rt*2+1,mid+1,r);
	tr[rt].sum=tr[rt*2].sum|tr[rt*2+1].sum;
}
void pushdown(int rt)
{
    if(!tr[rt].tag) 
		return;
	tr[rt*2].tag=tr[rt].tag;
	tr[rt*2+1].tag=tr[rt].tag;
	tr[rt*2].sum=tr[rt].tag;
	tr[rt*2+1].sum=tr[rt].tag;
    tr[rt].tag=0;
}
void update(int rt,int L,int R,int c)
{
	int l=tr[rt].l;
	int r=tr[rt].r;
	if(l>=L&&r<=R)
	{
		tr[rt].sum=tr[rt].tag=c;
		return;
	}
	pushdown(rt);
	int mid=(l+r)/2;
	if(L<=mid)
		update(rt*2,L,R,c);
	if(R>mid)
		update(rt*2+1,L,R,c);
	tr[rt].sum=tr[rt*2].sum|tr[rt*2+1].sum;
}
int query(int rt,int L,int R)
{
	int l=tr[rt].l;
	int r=tr[rt].r;
	if(l>=L&&r<=R)
		return tr[rt].sum;
	pushdown(rt);
	int mid=(l+r)/2,res=0;
	if(L<=mid)
		res|=query(rt*2,L,R);
	if(R>mid)
		res|=query(rt*2+1,L,R);
	return res;
}
char s[100];
int main()
{
	cin>>l>>t>>o;
	build(1,1,100000);
	for(int i=1;i<=o;++i)
	{
		scanf("%s",s+1);
		if(s[1]=='C')
		{
			int L,R,d;
			scanf("%d%d%d",&L,&R,&d);
			if(L>R)
				swap(L,R);
			update(1,L,R,1<<(d-1));
		}
		if(s[1]=='P')
		{
			int L,R;
			scanf("%d%d",&L,&R);
			if(L>R)
				swap(L,R);
			int res=query(1,L,R),ans=0;
			while(res)
			{
				ans+=res&1;
				res/=2;
			}
			printf("%d\n",ans);
		}
	}	
	return 0;
}
/*
6 3 4
C 2 3 2 
C 3 4 3
P 1 5
*/