算法优化专题 C POJ-2777

【题目大意】
长度为L的板被分成L段,每段长一个单位长度 (1 <= L <= 100000),
有O个操作 (1 <= O <= 100000)
操作分两种
C A B C 表示将区间[A,B]染成颜色C (1 <= C <= 30)
P A B 输出[A,B]有多少种不同的颜色
开始时[1,L]的颜色为1
【解题思路】
观察颜色的种数最多为30种。因此可以建30颗线段树。tree[x]i表示有无这种颜色i。
【代码】

#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std; 
int L,T,O;
bool tree[400004][35]; 
int d[400004];
bool ans[35];
void build_tree(int l,int r,int root)
{
	tree[root][1]=true;
	if (l==r) return;
	int mid=(l+r)/2;
	build_tree(l,mid,root*2);
	build_tree(mid+1,r,root*2+1);
}
void down(int root)
{
	int Lson=root*2;
	int Rson=root*2+1;
	int sym=d[root];
	for (int i=1;i<=T;i++)
	  {
	  tree[Lson][i]=false;
	  tree[Rson][i]=false;
      }
    tree[Lson][sym]=true;
	tree[Rson][sym]=true;
	d[root]=0;
	d[Lson]=sym;
	d[Rson]=sym;  
}
void update(int l,int r,int L,int R,int root,int c)
{
	if (r<L || l>R) return;
	if (l>=L && r<=R)
	{
		for (int i=1;i<=T;i++)
		  tree[root][i]=false;
		tree[root][c]=true;
		d[root]=c;
		return;  
	}
	int mid=(l+r)/2;
	if (d[root]!=0) down(root);
	update(l,mid,L,R,root*2,c);
	update(mid+1,r,L,R,root*2+1,c);
	for (int i=1;i<=T;i++)
	  tree[root][i]=(tree[root*2][i] | tree[root*2+1][i]);
}
void query(int l,int r,int L,int R,int root)
{
	if (r<L || l>R) return;	
	if (l>=L && r<=R)
	{
		for (int i=1;i<=T;i++)
		  ans[i]=(ans[i] | tree[root][i]);
		return;  
	}
	int mid=(l+r)/2;
	if (d[root]!=0) down(root);
	query(l,mid,L,R,root*2);
	query(mid+1,r,L,R,root*2+1);
	for (int i=1;i<=T;i++)
	  tree[root][i]=(tree[root*2][i] | tree[root*2+1][i]);
}
int main()
{
	freopen("c.in","r",stdin);
	freopen("c.out","w",stdout);
	scanf("%d%d%d",&L,&T,&O);
	build_tree(1,L,1);
	for (int i=1;i<=O;i++)
	  {
	  	char ch;
	  	cin>>ch;
	  	if (ch=='C')
	  	{
	  		int A,B,C;
	  		if (A>B) swap(A,B);
	  		scanf("%d%d%d",&A,&B,&C);
	  		update(1,L,A,B,1,C);
	  	}
	  	if (ch=='P')
	  	{
	  		int A,B;
	  		scanf("%d%d",&A,&B);
	  		if (A>B) swap(A,B);
	  		memset(ans,false,sizeof(ans));
	  		query(1,L,A,B,1);
	  		int t=0;
	  		for (int i=1;i<=T;i++)
	  		  if (ans[i]) t++;
	  		printf("%d\n",t);  
	  	}
	  }
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值