Luogu P1558 色板游戏【线段树/状态压缩】By cellur925

题目传送门

今天非常想再看一遍霸王别姬想不进去题于是开始刷数据结构

注意到至多只有\(30\)种颜色,啊啊啊啊我一开始竟然想的不是状态压缩而是在线段树中存一个30大小的数组,这样每次更新的时候暴力循环一遍。hhhhh。

可能这样比较好想吧,但是比正解状态压缩一下不知道差到哪里去了:)。开始还智障地把每次循环的次数开成30,那给出的色板数有什么用hh,这样是80分,改后AC。

#include<cstdio>
#include<algorithm>
#define maxn 100090

using namespace std;

int n,Q,tot;
char op[10];
struct SegmentTree{
	int l,r;int lazy;
	int col[35];
}t[maxn*4];

void re(int &x)
{
	x=0;
	char ch=getchar();
	bool flag=false;
	while(ch<'0'||ch>'9') flag|=(ch=='-'),ch=getchar();
	while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
	x=flag ? -x : x;
}

void build(int p,int l,int r)
{
	t[p].l=l,t[p].r=r;
	if(l==r)
	{
		t[p].col[1]=1;
		return ;
	}
	int mid=(l+r)>>1;
	build(p<<1,l,mid);
	build(p<<1|1,mid+1,r);
	t[p].col[1]=t[p<<1].col[1]+t[p<<1|1].col[1];
}

void update(int p)
{
	if(!t[p].lazy||t[p].l==t[p].r) return ;
	t[p<<1].lazy=t[p].lazy;t[p<<1|1].lazy=t[p].lazy;
	for(int i=1;i<=tot;i++)
		t[p<<1].col[i]=0,t[p<<1|1].col[i]=0;
	t[p<<1].col[t[p].lazy]+=t[p<<1].r-t[p<<1].l+1;
	t[p<<1|1].col[t[p].lazy]+=t[p<<1|1].r-t[p<<1|1].l+1;
	t[p].lazy=0;
}

void change(int p,int l,int r,int id)
{
	update(p);
	if(t[p].l==l&&t[p].r==r)
	{
		for(int i=1;i<=tot;i++)
			t[p].col[i]=0;
		t[p].col[id]+=r-l+1;
		t[p].lazy=id;
		return ;
	}
	int mid=(t[p].l+t[p].r)>>1;
	if(l>mid) change(p<<1|1,l,r,id);
	else if(r<=mid) change(p<<1,l,r,id);
	else change(p<<1,l,mid,id),change(p<<1|1,mid+1,r,id);
	for(int i=1;i<=tot;i++)
		t[p].col[i]=t[p<<1].col[i]+t[p<<1|1].col[i];
}

int ask(int p,int l,int r,int id)
{
	update(p);
	if(t[p].l==l&&t[p].r==r) return t[p].col[id];
	int mid=(t[p].l+t[p].r)>>1;
	if(l>mid) return ask(p<<1|1,l,r,id);
	else if(r<=mid) return ask(p<<1,l,r,id);
	else return ask(p<<1,l,mid,id)+ask(p<<1|1,mid+1,r,id);
}

int main()
{
	scanf("%d%d%d",&n,&tot,&Q);
	build(1,1,n);	
	while(Q--)
	{
		scanf("%s",op+1);
		if(op[1]=='C')
		{
			int x=0,y=0,z=0;
			scanf("%d%d%d",&x,&y,&z);
			if(x>y) swap(x,y);
			change(1,x,y,z);
		}
		else if(op[1]=='P')
		{
			int x=0,y=0;
			scanf("%d%d",&x,&y);
			if(x>y) swap(x,y);
			int cnt=0;
			for(int i=1;i<=tot;i++)
				if(ask(1,x,y,i)>0) cnt++;
			printf("%d\n",cnt);
		}
	}
	return 0;
}

最正确的做法是把每个节点的色板情况压成一个状态数,更新的时候用位运算更新==。这种方法我没有写,找了一个大佬写的:传送门

posted @ 2018-11-03 19:20  cellur925&Chemist  阅读(385)  评论(0编辑  收藏  举报