高质量题集合

发布时间 2023-07-27 09:42:51作者: Eon_Sky

\(\color{royalblue}{P5522\ [yLOI2019]\ 棠梨煎雪}\)

思路:线段树+状压

复杂度:\(O(nq+q\log_2m)\)

主体思路

第一眼想到开 \(30\) 个线段树维护每一位上的 \(0/1/?\) ,复杂度 \(O(nq\log_2m)\)。考虑把每个字符串的 \(0/1/?\) 状压压进线段树,优化为正解。

具体地,开三个线段树维护 \(l\)\(r\) 之间每一位是否出现 \(0/1/?\),用 \(or\) 转移,对于答案分几类讨论即可。

\(\text{code:}\)

#define LL long long
#define UN unsigned
#include<bits/stdc++.h>
using namespace std;
//--------------------//
const int N=31,M=1e5+9;

int n,m,q;
char a[M][N],temp[N];
int tem0[M],tem1[M],tem[M];
int ans;
//--------------------//
//Seg-Tree
const int TM=4e5+30;

struct Seg_Tree
{
    struct Seg_Tree_Node
    {
        int l,r;
        int val;
    }t[TM];
    int s[M];

    int ls(int rt){return rt<<1;}
    int rs(int rt){return rt<<1|1;}

    void push_up(int rt){t[rt].val=t[ls(rt)].val|t[rs(rt)].val;}

    void build(int rt,int l,int r)
    {
        t[rt].l=l,t[rt].r=r;
        if(l==r)
        {
            t[rt].val=s[l];
            return;
        }
        int mid=l+r>>1;
        build(ls(rt),l,mid);
        build(rs(rt),mid+1,r);
        push_up(rt);
        return;
    }

    void change(int rt,int pos,int val)
    {
        if(t[rt].l==t[rt].r)
        {
            t[rt].val=val;
            return;
        }
        int mid=t[rt].l+t[rt].r>>1;
        if(pos<=mid)
            change(ls(rt),pos,val);
        else
            change(rs(rt),pos,val);
        push_up(rt);
        return;
    }

    int query(int rt,int l,int r)
    {
        if(t[rt].l>=l&&t[rt].r<=r)
            return t[rt].val;
        int mid=t[rt].l+t[rt].r>>1,res=0;
        if(l<=mid)
            res|=query(ls(rt),l,r);
        if(r>mid)
            res|=query(rs(rt),l,r);
        return res;
    }
}T0,T1,T;
//--------------------//
int count(int x)
{
    int res=0;
    while(x)
    {
        res+=x&1;
        x>>=1;
    }
    return res;
}
int qpow(int base,int k)
{
    int res=1;
    while(k)
    {
        if(k&1)
            res*=base;
        base*=base;
        k>>=1;
    }
    return res;
}
//--------------------//
int main()
{
    scanf("%d%d%d",&n,&m,&q);
    for(int i=1;i<=m;i++)
    {
        scanf("%s",a[i]+1);
        for(int j=1;j<=n;j++)
        {
            if(a[i][j]=='0')
                tem0[i]+=1<<(j-1);
            else if(a[i][j]=='1')
                tem1[i]+=1<<(j-1);
            else 
                tem[i]+=1<<(j-1);
        }
    }
    for(int i=1;i<=m;i++)
    {
        T0.s[i]=tem0[i];
        T1.s[i]=tem1[i];
        T.s[i]=tem[i];
        //printf("%d %d %d %d\n",i,tem0[i],tem1[i],tem[i]);
    }
    T0.build(1,1,m);
    T1.build(1,1,m);
    T.build(1,1,m);
    int nowans,now0,now1,now;
    for(int op,x,y,i=1;i<=q;i++)
    {
        scanf("%d%d",&op,&x);
        if(op==0)
        {
            scanf("%d",&y);
            now0=T0.query(1,x,y);
            now1=T1.query(1,x,y);
            now=T.query(1,x,y);
            if(now0&now1)
                nowans=0;
            else
                nowans=qpow(2,count(now^(now&now0)^(now&now1)));
            //printf("%d %d %d %d\n",nowans,now0,now1,now);
            ans^=nowans;
        }
        else
        {
            scanf("%s",temp+1);
            now0=now1=now=0;
            for(int j=1;j<=n;j++)
            {
                if(temp[j]=='0')
                    now0+=1<<(j-1);
                else if(temp[j]=='1')
                    now1+=1<<(j-1);
                else 
                    now+=1<<(j-1);
            }
            T0.change(1,x,now0);
            T1.change(1,x,now1);
            T.change(1,x,now);
        }
    }
    printf("%d",ans);
    return 0;
}