POJ - 2777 - Count Color (线段树二进制区间染色)

题目:POJ-2777

题意:给出n的长度的木棒,初始的颜色都为1,给出num中颜色,给出m个操作, C l r x 将l到r内的所有颜色更改为x , P l r 问在l到r内有多少种颜色

题解:初始化肯定都是颜色1,就表示只有一种颜色,然后每次更新颜色时,取这个数的a[x]=1<<(Item-1),a[x]中的1的位置就表示每个颜色的位置,那么这样或过去就可以查找出有多少种颜色了

然后pushup操作就改为:a[x]=a[x*2]|a[x*2+1],a[x]中的1的个数就是这个区间颜色的个数。对于Item为什么要-1,其实就是初始颜色时1,就相当于从第0位开始,与数组的0-n-1类似。

最后注意不要用ans1|ans2(其中ans1跟ans2是自己定义的变量),因为这样居然RE了,感觉天衣无缝

AC代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#define N 110000
#define lson node<<1
#define rson node<<1|1
using namespace std;
int n,k,m;
struct ljh
{
	int l,r,sum,lazy;
}e[N*4];
void pushup(int node)
{
	e[node].sum=(e[lson].sum|e[rson].sum);                                                                                                               
}
void pushdown(int node)
{
	if(e[node].lazy!=0)
	{
		e[lson].sum=e[node].lazy;
		e[lson].lazy=e[node].lazy;
		e[rson].sum=e[node].lazy;
		e[rson].lazy=e[node].lazy;
		e[node].lazy=0;
	}
}
void build(int node,int l,int r)
{
	e[node].l=l;
	e[node].r=r;
	e[node].sum=0;
	e[node].lazy=0;
	if(l==r)
	{
		e[node].sum=1;
		return ;
	}
	int m=(l+r)>>1;
	build(lson,l,m);
	build(rson,m+1,r);
	pushup(node);
}
void update(int node,int x,int y,int z)
{
	if(x<=e[node].l&&e[node].r<=y)
	{
		e[node].sum=1<<(z-1);
		e[node].lazy=1<<(z-1);
		return ;
	}
	pushdown(node);
	int m=(e[node].l+e[node].r)>>1;
	if(x<=m)update(lson,x,y,z);
	if(y>m)update(rson,x,y,z);
	pushup(node);
}
int query(int node,int x,int y)
{
	if(e[node].l>y||e[node].r<x)
	{
		return 0;
	}
	// int ans=0,sum=0;
	if(x<=e[node].l&&e[node].r<=y)
	{
		return e[node].sum;
	}
	pushdown(node);
	// if(x<=m)ans=query(lson,x,y);
	// if(y>m)sum=query(rson,x,y);
	// return (ans|sum);
	return query(lson,x,y)|query(rson,x,y);
}
int ans(int x)
{
	int temp=0;
	// cout<<x<<endl;
	while(x)
	{
		// cout<<x<<endl;
		if(x&1)temp++;
		x>>=1;
	}
	return temp;
}
int main()
{
	while(~scanf("%d%d%d",&n,&k,&m))
	{
		build(1,1,n);
		while(m--)
		{
			char op;
			int x,y,z;
			// getchar();
			cin>>op;
			// cout<<op<<endl;
			if(op=='C')
			{
				scanf("%d%d%d",&x,&y,&z);
				if(x>y)swap(x,y);
				update(1,x,y,z);
			}
			if(op=='P')
			{
				scanf("%d%d",&x,&y);
				if(x>y)swap(x,y);
				printf("%d\n",ans(query(1,x,y)));
			}
		}
	}
	return 0;
}

附上之前写T了的代码,虽然不知道为啥会T,感觉跟AC代码比起来,查找的时间复杂度差不多???甚至还快些???

T了的代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<queue>
#include<vector>
#include<map>
#include<algorithm>
#define N 100005
#define lson node<<1
#define rson node<<1|1
using namespace std;
int L,m,n,vis[35],ans;
struct ljh
{
	int l,r,sum;
}e[N<<2];
void build(int node,int l,int r)
{
	// cout<<l<<" "<<r<<endl;
	e[node].sum=1;
	e[node].l=l;
	e[node].r=r;
	if(l==r)return ;
	int m=(l+r)>>1;
	build(lson,l,m);
	build(rson,m+1,r);
}
void pushdown(int node)
{
	if(e[node].sum!=-1)
	{
		e[lson].sum=e[node].sum;
		e[rson].sum=e[node].sum;
		e[node].sum=-1;
	}
}
void pushup(int node)
{
	if(e[lson].sum==e[rson].sum)
		e[node].sum=e[lson].sum;
}
void update(int node,int x,int y,int z)
{
	// cout<<node<<endl;
	if(x<=e[node].l&&e[node].r<=y)
	{
		e[node].sum=z;
		return;
	}
	pushdown(node);
	int m=(e[node].l+e[node].r)>>1;
	if(x<=m)update(lson,x,y,z);
	if(y>m)update(rson,x,y,z);
	pushup(node);
}
void query(int node,int x,int y)
{
	// cout<<node<<" "<<e[node].l<<" "<<e[node].r<<" "<<e[node].sum<<endl;
	if(e[node].sum!=-1&&!vis[e[node].sum])
	{
		ans++;
		vis[e[node].sum]=1;
		return;
	}
	if(e[node].l==e[node].r)return;
	pushdown(node);
	int m=(e[node].l+e[node].r)>>1;
	if(x<=m)query(lson,x,y);
	if(y>m)query(rson,x,y);
	pushup(node);
}
int main()
{
	while(~scanf("%d%d%d",&L,&n,&m))
	{
		build(1,1,L);
		while(m--)
		{
			char op;
			int x,y,z;
			// getchar();
			cin>>op;
			// cout<<op<<endl;
			if(op=='C')
			{
				scanf("%d%d%d",&x,&y,&z);
				// if(x>y)swap(x,y);
				update(1,x,y,z);
			}
			if(op=='P')
			{
				memset(vis,0,sizeof(vis));
				scanf("%d%d",&x,&y);
				ans=0;
				// if(x>y)swap(x,y);
				query(1,x,y);
				printf("%d\n",ans);
			}
		}
	}
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值