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;
}
最正确的做法是把每个节点的色板情况压成一个状态数,更新的时候用位运算更新==。这种方法我没有写,找了一个大佬写的:传送门
独立意志与自由思想是必须争的,且须以生死力争。