题解:P13274 [NOI2025] 三目运算符

· · 题解

\Large\textup{\textmd{Solution}}

线段树。

考虑对于字符串每一位 i,影响到这一位的只会有第 i 位,第 i-1 位和 i-2 位,手搓 3 位字符串可以发现:

考虑用线段树维护这个操作,记录内容如下:

\Large\textup{\textmd{Instruction}}

\textup{\textbf{Pushup}}

更新区间维护的所有信息。

对于每个点,设其为 x,其左子树为 ls,其右子树为 rs

\textup{\textbf{Pushdown}}

交换对应的每一组两个数,更新懒标记。

\textup{\textbf{Inital Value}}

\Large\textup{\textmd{Code}}

#include<bits/stdc++.h>
#define int long long
#define tag(x) st[x].tag
#define vl0(x) st[x].vl0
#define vl1(x) st[x].vl1
#define ls(x) st[x].ls
#define rs(x) st[x].rs
#define b0(x) st[x].b0
#define b1(x) st[x].b1
#define l0(x) st[x].l0
#define l1(x) st[x].l1
#define r0(x) st[x].r0
#define r1(x) st[x].r1
#define lsz mid-l+1
#define rsz r-mid
#define sz r-l+1
using namespace std;
const int N=800010;
int n,m,a[N];
struct treenode{
    int ls,rs,b0,b1,l0,l1,r0,r1,vl0,vl1,tag;
}st[N];
struct segtree{
    int rt,tc;
    void pushup(int x,int l,int r){ // 同上描述
        int mid=(l+r)>>1;
        vl0(x)=max(vl0(ls(x)),vl0(rs(x)));
        vl1(x)=max(vl1(ls(x)),vl1(rs(x)));
        if(r0(ls(x))&&l0(rs(x))){
            b0(x)=min(mid+l0(rs(x))-1,b0(rs(x)));
            if(b0(ls(x))<mid-r0(ls(x))+1) b0(x)=min(b0(x),b0(ls(x)));
        }else b0(x)=min(b0(ls(x)),b0(rs(x)));
        if(r1(ls(x))&&l1(rs(x))){
            b1(x)=min(mid+l1(rs(x))-1,b1(rs(x)));
            if(b1(ls(x))<mid-r1(ls(x))+1) b1(x)=min(b1(x),b1(ls(x)));
        }else b1(x)=min(b1(ls(x)),b1(rs(x)));
        l0(x)=(l0(ls(x))!=lsz?l0(ls(x)):lsz+l0(rs(x)));
        l1(x)=(l1(ls(x))!=lsz?l1(ls(x)):lsz+l1(rs(x)));
        r0(x)=(r0(rs(x))!=rsz?r0(rs(x)):rsz+r0(ls(x)));
        r1(x)=(r1(rs(x))!=rsz?r1(rs(x)):rsz+r1(ls(x)));
        if((r0(ls(x))&&l1(rs(x))==1&&rsz>1)||(r1(ls(x))==1&&l0(rs(x))&&lsz>1)) vl0(x)=max(vl0(x),1ll);
        if((r0(ls(x))==1&&l1(rs(x))&&lsz>1)||(r1(ls(x))&&l0(rs(x))==1&&rsz>1)) vl1(x)=max(vl1(x),1ll);
    }
    void pushdown(int x){ // 同上描述
        if(!tag(x)) return;
        tag(ls(x))^=tag(x); 
        tag(rs(x))^=tag(x); 
        swap(vl0(ls(x)),vl1(ls(x))),swap(vl0(rs(x)),vl1(rs(x)));
        swap(b0(ls(x)),b1(ls(x))),  swap(b0(rs(x)),b1(rs(x)));
        swap(l0(ls(x)),l1(ls(x))),  swap(l0(rs(x)),l1(rs(x)));
        swap(r0(ls(x)),r1(ls(x))),  swap(r0(rs(x)),r1(rs(x)));
        tag(x)=0;
    }
    void build(int &x,int l,int r){
        x=++tc;
        tag(x)=0;
        b0(x)=b1(x)=2*n;
        vl0(x)=vl1(x)=0;
        l1(x)=r1(x)=l0(x)=r0(x)=0;
        if(l==r){
            if(a[l]){ // 根据输入更新
                l1(x)=r1(x)=1;
                l0(x)=r0(x)=0;
            }else{
                l1(x)=r1(x)=0;
                l0(x)=r0(x)=1;
            }
            return;
        }
        int mid=(l+r)>>1;
        build(ls(x),l,mid);
        build(rs(x),mid+1,r);
        pushup(x,l,r);
    }
    void update(int x,int l,int r,int ql,int qr){
        if(ql<=l&&r<=qr){
            tag(x)^=1;
            swap(vl0(x),vl1(x));
            swap(b0(x),b1(x));
            swap(l0(x),l1(x));
            swap(r0(x),r1(x));
            return;
        }
        pushdown(x);
        int mid=(l+r)>>1;
        if(ql<=mid) update(ls(x),l,mid,ql,qr);
        if(mid<qr) update(rs(x),mid+1,r,ql,qr);
        pushup(x,l,r);
    }
    int query(){
        int ans=vl1(rt);
        if(b1(rt)!=2*n) ans=max(ans,n-b1(rt)-1); // 输出答案为 vl1 和 b1 位置更新到末尾的最大值
        return ans;
    }
    void print(int x,int l,int r){ // 调试用
        cout<<x<<"|"<<l<<"|"<<r<<"|\tvl0 "<<vl0(x)<<"\tvl1 "<<vl1(x)<<"\tl0 "<<l0(x)<<"\tl1 "<<l1(x)<<"\tr0 "<<r0(x)<<"\tr1 "<<r1(x)<<"\tb0 "<<b0(x)<<"\tb1 "<<b1(x)<<"\n";
        pushdown(x);
        if(l==r) return;
        int mid=(l+r)>>1;
        print(ls(x),l,mid);
        print(rs(x),mid+1,r);
    }
}t;

signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    int T;
    cin>>T>>T;
    while(T--){
        t.tc=0;
        cin>>n>>m;
        char c;
        for(int i=1;i<=n;i++){
            cin>>c;
            a[i]=c-'0';
        }
        t.build(t.rt,1,n);
//      t.print(t.rt,1,n);
//      cout<<t.query()<<"\n";
        int l,r,ans=0;
        ans=t.query();
        for(int i=2;i<=m+1;i++){
            cin>>l>>r;
            t.update(t.rt,1,n,l,r);
//          t.print(t.rt,1,n);
//          cout<<t.query()<<"\n";
            ans^=i*t.query();
        }
        cout<<ans<<"\n";
    }
    return 0;
}