题解:P6781 [Ynoi2008] rupq

题面传送门

题意

给出一个括号串,每个括号有权值,支持单点修改,区间移动,查询区间中匹配括号对消掉之后所有权值的 \(\text{max}\)\(\text{NAND}\)

思路

首先一个区间剩下的肯定是左边一段右括号和右边一段左括号。如果我们要做两个区间合并,那么肯定会消掉中间的一些括号对,且维护的信息不具有可差分性。根据这样的结构容易想到单侧递归。然后这个题要求 \(\text{polylog}\) 支持区间移动,于是考虑用平衡树维护。

于是我们对于平衡树上的每个节点维护这个节点子树代表的区间最后会剩下什么,以及左右儿子互相抵消后各自的结果。在 \(\text{pushup}\) 时求出一边要删除多少个左或右括号,然后单侧递归即可。

这样子维护 \(\text{max}\) 就是容易的了,维护 \(\text{NAND}\) 时可以直接压位维护每一位上左边 \(\text{NAND}\) 上一个 \(0\)\(1\) 的结果,然后也能直接合并了。

建树的时候注意线性建树,时间复杂度 \(\mathcal{O}(n\log n+m\log^2n)\)

实现细节

本题卡常。在 \(\text{pushup}\) 时,容易注意到左边的左括号和右边的右括号至少有一个被消完,所以只要做一次单侧递归。如果使用 FHQTreap 维护需要支持三个区间合并,常数较大,建议使用分裂合并维护的 WBLT。

代码

#include <bits/stdc++.h>
using namespace std;
constexpr int N=2e6+6;
constexpr double w=0.29;
struct Node{int len;unsigned maxn,f0,f1;}l[N<<1],r[N<<1],lsr[N<<1],rsl[N<<1];
Node operator+(const Node&x,const Node&y){
    return{
        x.len+y.len,
        x.maxn>y.maxn?x.maxn:y.maxn,
        (x.f0&y.f1)|(~x.f0&y.f0),
        (x.f1&y.f1)|(~x.f1&y.f0)
    };
}
unsigned calc(Node x){return x.maxn^x.f1;}
int n,m,ls[N<<1],rs[N<<1],size[N<<1],rt,cnt;
int st[N],top;
unsigned b[N],val[N<<1];
bool a[N],c[N<<1];
int newnode(bool x,unsigned y){
    int p;if(!top)p=++cnt;
    else p=st[top--];
    ls[p]=rs[p]=0;
    c[p]=x;
    val[p]=y;
    if(x)l[p]={0,0,0,-1u},r[p]={1,y,-1u,~y};
    else r[p]={0,0,0,-1u},l[p]={1,y,-1u,~y};
    size[p]=1;
    return p;
}
Node lq(int p,int x){
    if(!p)return {0,0,0,-1u};
    if(x<=0)return l[p];
    if(x>=l[p].len)return {0,0,0,-1u};
    if(l[ls[p]].len<=x)return lq(rs[p],x-l[ls[p]].len+r[ls[p]].len);
    return lq(ls[p],x)+rsl[p];
}
Node rq(int p,int x){
    if(!p)return {0,0,0,-1u};
    if(x<=0)return r[p];
    if(x>=r[p].len)return {0,0,0,-1u};
    if(r[rs[p]].len<=x)return rq(ls[p],x-r[rs[p]].len+l[rs[p]].len);
    return lsr[p]+rq(rs[p],x);
}
void pushup(int p){
    if(!ls[p])return;
    size[p]=size[ls[p]]+size[rs[p]];
    if(r[ls[p]].len<=l[rs[p]].len){
        rsl[p]=lq(rs[p],r[ls[p]].len);
        lsr[p]={0,0,0,-1u};
        l[p]=l[ls[p]]+rsl[p];
        r[p]=r[rs[p]];
    }else{
        lsr[p]=rq(ls[p],l[rs[p]].len);
        rsl[p]={0,0,0,-1u};
        l[p]=l[ls[p]];
        r[p]=lsr[p]+r[rs[p]];
    }
}
int build(int pl,int pr){
    if(pl==pr)return newnode(a[pl],b[pl]);
    int p;if(!top)p=++cnt;
    else p=st[top--];
    const int mid=(pl+pr)>>1;
    ls[p]=build(pl,mid);
    rs[p]=build(mid+1,pr);
    pushup(p);
    return p;
}
int merge(int rtl,int rtr){
    if(!rtl||!rtr)return rtl|rtr;
    if(min(size[rtl],size[rtr])>=w*(size[rtl]+size[rtr])){
        int p;if(!top)p=++cnt;
        else p=st[top--];
        ls[p]=rtl,rs[p]=rtr;
        pushup(p);
        return p;
    }
    if(size[rtl]>=size[rtr]){
        if(size[ls[rtl]]>=w*(size[rtl]+size[rtr])){
            rs[rtl]=merge(rs[rtl],rtr);
        }else{
            ls[rtl]=merge(ls[rtl],ls[rs[rtl]]);
            st[++top]=rs[rtl];
            rs[rtl]=merge(rs[rs[rtl]],rtr);
        }
        pushup(rtl);
        return rtl;
    }else{
        if(size[rs[rtr]]>=w*(size[rtl]+size[rtr])){
            ls[rtr]=merge(rtl,ls[rtr]);
        }else{
            rs[rtr]=merge(rs[ls[rtr]],rs[rtr]);
            st[++top]=ls[rtr];
            ls[rtr]=merge(rtl,ls[ls[rtr]]); 
        }
        pushup(rtr);
        return rtr;
    }
}
void split(int p,int rank,int&rtl,int&rtr){
    if(!p){rtl=rtr=0;return;}
    if(!ls[p]){
        if(rank)rtl=p,rtr=0;
        else rtl=0,rtr=p;
        return;
    }
    if(rank<=size[ls[p]]){
        split(ls[p],rank,rtl,rtr);
        st[++top]=p;
        rtr=merge(rtr,rs[p]);
    }else{
        split(rs[p],rank-size[ls[p]],rtl,rtr);
        st[++top]=p;
        rtl=merge(ls[p],rtl);
    }
}
void update(int p,int pos,unsigned x){
    if(!ls[p]){
        val[p]=x;
        c[p]^=1;
        if(c[p])l[p]={0,0,0,-1u},r[p]={1,x,-1u,~x};
        else r[p]={0,0,0,-1u},l[p]={1,x,-1u,~x};
        return;
    }
    if(pos<=size[ls[p]])update(ls[p],pos,x);
    else update(rs[p],pos-size[ls[p]],x);
    pushup(p);
}
void query(int p,int l,int r,vector<int>&pos){
    if(l==1&&r==size[p]){pos.push_back(p);return;}
    if(l>size[ls[p]])return query(rs[p],l-size[ls[p]],r-size[ls[p]],pos);
    if(r<=size[ls[p]])return query(ls[p],l,r,pos);
    query(ls[p],l,size[ls[p]],pos);
    query(rs[p],1,r-size[ls[p]],pos);
}
void print(int p){
    if(!ls[p])return;
    cout<<p<<' '<<ls[p]<<'\n'<<p<<' '<<rs[p]<<'\n';
    print(ls[p]);
    print(rs[p]);
}
int id[N];
Node v[N],s[N];
signed main(){
    clock_t _st=clock();
    ios::sync_with_stdio(false);
    cin.tie(0),cout.tie(0);
    cin>>n>>m;
    for(int i=1;i<=n;i++)cin>>a[i]>>b[i];
    rt=build(1,n);
    s[0]={0,0,0,-1u};
    for(int i=1;i<=m;i++){
        int op,x,y;cin>>op>>x>>y;
        if(op==1)update(rt,x,y);
        if(op==2){
            vector<int>res;
            query(rt,x,y,res);
            Node l=::l[res[0]];
            int top=0;
            id[++top]=res[0];
            v[top]=s[top]=::r[res[0]];
            for(int i=1;i<res.size();i++){
                if(s[top].len<=::l[res[i]].len){
                    l=l+lq(res[i],s[top].len);
                    id[top=1]=res[i];
                    v[top]=s[top]=::r[res[i]];
                }else{
                    int sum=::l[res[i]].len;
                    for(;top;top--){
                        if(v[top].len<=sum)sum-=v[top].len;
                        else{
                            v[top]=rq(id[top],r[id[top]].len-v[top].len+sum);
                            s[top]=s[top-1]+v[top];
                            break;
                        }
                    }
                    id[++top]=res[i];
                    s[top]=s[top-1]+(v[top]=::r[res[i]]);
                }
            }
            cout<<calc(l+s[top])<<'\n';
        }if(op==3){
            int rt1,rt2,rt3;
            split(rt,y,rt1,rt3);
            split(rt1,x-1,rt1,rt2);
            rt=merge(merge(rt1,rt3),rt2);
        }
    }
    clock_t _ed=clock();
    cerr<<(_ed-_st)*1.0/CLOCKS_PER_SEC<<'\n';
    return 0;
}
posted @ 2026-02-02 17:33  Redolent  阅读(1)  评论(0)    收藏  举报