P5232 [JSOI2012] 智者的考验

题意

对于一个 \(Rx\times Ry\) 的矩阵,有 \(Rx+Ry\) 中操作,每种操作为把一行 / 一列按位反转。同时给出一个特殊矩阵,称祂为厄运矩阵。
有一个长度为 \(n\) 的操作序列,初始操作全为 \(1\)
\(m\) 次询问,分为 \(3\) 种:区间修改,单点修改,区间查询有多少个操作满足操作有变成厄运矩阵。
\(n\le10^6,m\le1.2\times10^5\)

思路

把每个状态压成一个 \(5\) 位二进制,表示每个操作执行了奇数 / 偶数次,用线段树记录每个区间的变化状况,这个可以用一个二进制数表示。还要记录这个区间每个数出现了多少次,用来统计答案。
由于修改会把区间全部变成同一个按钮,相当于这个按钮按 \(0/1\) 次,可以用懒标记快速修改,查询时把那些区间 \(merge\) 起来就行了。
时间复杂度 \(\mathcal O(2^{Rx+Ry}m\log n)\)

代码

有点卡空间。
其中那些奇怪的结构体是用来优化空间的(让小区间开 unsigned short)。

// Problem: P5232 [JSOI2012] 智者的考验
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P5232
// Memory Limit: 250 MB
// Time Limit: 2000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include<bits/stdc++.h>
using namespace std;
namespace IO{
    template<typename T>
    inline void read(T&x){
        x=0;char c=getchar();bool f=0;
        while(!isdigit(c)) c=='-'?f=1:0,c=getchar();
        while(isdigit(c)) x=x*10+c-'0',c=getchar();
        f?x=-x:0;
    }
    template<typename T>
    inline void write(T x){
        if(x==0){putchar('0');return ;}
        x<0?x=-x,putchar('-'):0;short st[50],top=0;
        while(x) st[++top]=x%10,x/=10;
        while(top) putchar(st[top--]+'0');
    }
    inline void read(char&c){c=getchar();while(isspace(c)) c=getchar();}
    inline void write(char c){putchar(c);}
    inline void read(string&s){s.clear();char c;read(c);while(!isspace(c)&&~c) s+=c,c=getchar();}
    inline void write(string s){for(int i=0,len=s.size();i<len;i++) putchar(s[i]);}
    template<typename T>inline void write(T*x){while(*x) putchar(*(x++));}
    template<typename T,typename...T2> inline void read(T&x,T2&...y){read(x),read(y...);}
    template<typename T,typename...T2> inline void write(const T x,const T2...y){write(x),putchar(' '),write(y...),sizeof...(y)==1?putchar('\n'):0;}
}using namespace IO;
const int maxn=1000010;
int rx,ry,n,m,ey,a[10][10],o[32];
struct Realnode{
    unsigned short cnt[32];
    int ch,tag;
}tr[2097152];
int th[20][32];
class Segment_Tree{
private:
    struct node{
        int cnt[32],ch,tag;
        node(){memset(cnt,0,sizeof(cnt)),ch=tag=0;}
    };
    struct element{
        int u,i;
        operator int(){return(u<=16)?th[u][i]:tr[u].cnt[i];}
        element&operator=(int z){
            if(u<=16) th[u][i]=z;
            else tr[u].cnt[i]=z;
            return*this;
        }
    };
    struct cnt_dl{
        int u;
        element operator[](const int i){return {u,i};}
    };
    struct node_dl{
        int u,&ch,&tag;
        cnt_dl cnt;
        node_dl(int _u):u(_u),ch(tr[u].ch),tag(tr[u].tag),cnt({_u}){}
        void operator=(const node&o){
            ch=o.ch,tag=o.tag;
            if(u<=16) for(int i=0;i<(1<<rx+ry);i++) th[u][i]=o.cnt[i];
            else for(int i=0;i<(1<<rx+ry);i++) tr[u].cnt[i]=o.cnt[i];
        }
        operator node()const{
            node ans;
            ans.ch=ch,ans.tag=tag;
            if(u<=16) for(int i=0;i<(1<<rx+ry);i++) ans.cnt[i]=th[u][i];
            else for(int i=0;i<(1<<rx+ry);i++) ans.cnt[i]=tr[u].cnt[i];
            return ans;
        }
    };
    struct tree_dl{
        node_dl operator[](int u){return node_dl(u);}
    }t;
    node merge(node a,node b){
        node ans;
        ans.ch=a.ch^b.ch;
        for(int i=0;i<(1<<rx+ry);i++) ans.cnt[i]=a.cnt[i]+b.cnt[i^a.ch];
        return ans;
    }
    void add_tag(int u,int w,int l,int r){
        t[u].tag=w;
        int len=r-l+1;
        int z=(1<<w-1);
        if(len&1) t[u].ch=z;else t[u].ch=0;
        for(int i=0;i<(1<<rx+ry);i++) t[u].cnt[i]=0;
        t[u].cnt[0]=len/2;
        t[u].cnt[z]=(len+1)/2;
    }
    void down(int u,int l,int r){
        if(t[u].tag==0) return ;
        int mid=l+r>>1;
        add_tag(u<<1,t[u].tag,l,mid),add_tag(u<<1|1,t[u].tag,mid+1,r);
        t[u].tag=0;
    }
    void update(int u,int l,int r,int ll,int rr,int w){
        if(l>rr||r<ll) return ;
        if(ll<=l&&r<=rr){add_tag(u,w,l,r);return ;}
        down(u,l,r);
        int mid=l+r>>1;
        update(u<<1,l,mid,ll,rr,w),update(u<<1|1,mid+1,r,ll,rr,w);
        t[u]=merge(t[u<<1],t[u<<1|1]);
    }
    node query(int u,int l,int r,int ll,int rr){
        if(ll<=l&&r<=rr) return t[u];
        down(u,l,r);
        int mid=l+r>>1;
        if(rr<=mid) return query(u<<1,l,mid,ll,rr);
        if(ll>mid) return query(u<<1|1,mid+1,r,ll,rr);
        return merge(query(u<<1,l,mid,ll,rr),query(u<<1|1,mid+1,r,ll,rr));
    }
public:
    void update(int l,int r,int w){update(1,1,n,l,r,w);}
    int query(int l,int r){
        int zt=0,re=0;
        if(l>1) zt=query(1,1,n,1,l-1).ch;
        node ans=query(1,1,n,l,r);
        for(int i=0;i<(1<<rx+ry);i++) if(o[i^zt]==ey) re+=ans.cnt[i];
        return re;
    }
}t;
signed main(){
    read(rx,ry);
    for(int i=1;i<=rx;i++) for(int j=1;j<=ry;j++){
        int x;read(x);
        a[i][j]=x;
    }
    for(int i=rx;i>=1;i--) for(int j=ry;j>=1;j--) ey=ey*2+a[i][j];
    for(int i=0;i<(1<<rx+ry);i++){
        o[i]=0;
        for(int j=1;j<=rx;j++) for(int l=1;l<=ry;l++){
            bool f1=!(i&(1<<j-1)),f2=!(i&(1<<l+rx-1));
            if(f1^f2) o[i]^=(1<<(j-1)*ry+l-1);
        }
    }
    read(n,m);
    t.update(1,n,1);
    for(int i=1;i<=m;i++){
        int op,d,l,r,x;
        read(op);
        if(op==0){
            read(d,x);
            t.update(d,d,x);
        }
        if(op==1){
            read(l,r);
            write(t.query(l,r));
            write("\n");
        }
        if(op==2){
            read(l,r,x);
            t.update(l,r,x);
        }
    }
    return 0;
}
posted @ 2026-06-04 21:38  Link-Cut_Trees  阅读(31)  评论(0)    收藏  举报