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;
}

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

猜你喜欢

转载自www.cnblogs.com/nopartyfoucaodong/p/9901773.html
今日推荐