社区讨论

Maybe 新做法?

P2572[SCOI2010] 序列操作参与者 5已保存回复 6

讨论操作

快速查看讨论及其快照的属性,并进行相关操作。

当前回复
6 条
当前快照
1 份
快照标识符
@mjli0qmf
此快照首次捕获于
2025/12/25 21:48
2 个月前
此快照最后确认于
2025/12/27 19:25
2 个月前
查看原帖
先上代码:
CPP
#include<bits/stdc++.h>
//#define int long long
#define mid ((l+r)>>1)
using namespace std;
const int maxn=1e5+5;
int n,m;
bool a[maxn];
int cnt=0;
struct Node{
    int sum=0,pre=0,suf=0;
};
int rt0,rt1;
struct SegmentTree{
    int lc[maxn<<3],rc[maxn<<3],tot[maxn<<3];
    int tag[maxn<<3],pre[maxn<<3],suf[maxn<<3],sum[maxn<<3];
    void pushup(int o,int l,int r){
        if(pre[lc[o]]==mid-l+1)pre[o]=pre[lc[o]]+pre[rc[o]];
        else pre[o]=pre[lc[o]];
        if(suf[rc[o]]==r-mid)suf[o]=suf[rc[o]]+suf[lc[o]];
        else suf[o]=suf[rc[o]];
        sum[o]=max(max(sum[lc[o]],sum[rc[o]]),suf[lc[o]]+pre[rc[o]]);
        tot[o]=tot[lc[o]]+tot[rc[o]];
    }
    void pushdown(int o,int l,int r){
        if(tag[o]==-1)return;
        tag[lc[o]]=tag[rc[o]]=tag[o];
        if(tag[o]){
            pre[lc[o]]=suf[lc[o]]=sum[lc[o]]=tot[lc[o]]=mid-l+1;
            pre[rc[o]]=suf[rc[o]]=sum[rc[o]]=tot[rc[o]]=r-mid;
        }else{
            pre[lc[o]]=suf[lc[o]]=sum[lc[o]]=tot[lc[o]]=0;
            pre[rc[o]]=suf[rc[o]]=sum[rc[o]]=tot[rc[o]]=0;
        }
        tag[o]=-1;
    }
    void build(int &o,int l,int r){
        if(!o)o=++cnt;
        tag[o]=-1;
        if(l==r){
            if(a[l])pre[o]=suf[o]=sum[o]=tot[o]=1;
            else pre[o]=suf[o]=sum[o]=tot[o]=0;
            return;
        }
        build(lc[o],l,mid);
        build(rc[o],mid+1,r);
        pushup(o,l,r);
    }
    void update(int o,int l,int r,int L,int R,bool k){
        if(L<=l&&r<=R){
            tag[o]=k;
            if(k){
                pre[o]=suf[o]=sum[o]=tot[o]=r-l+1;
            }else{
                pre[o]=suf[o]=sum[o]=tot[o]=0;
            }
            return;
        }
        pushdown(o,l,r);
        if(L<=mid)update(lc[o],l,mid,L,R,k);
        if(R>mid)update(rc[o],mid+1,r,L,R,k);
        pushup(o,l,r);
    }
    int queryTot(int o,int l,int r,int L,int R){
        if(L<=l&&r<=R){
            return tot[o];
        }
        pushdown(o,l,r);
        int ans=0;
        if(L<=mid)ans+=queryTot(lc[o],l,mid,L,R);
        if(R>mid)ans+=queryTot(rc[o],mid+1,r,L,R);
        return ans;
    }
    Node querySum(int o,int l,int r,int L,int R){
        if(L<=l&&r<=R){
            return {sum[o],pre[o],suf[o]};
        }
        pushdown(o,l,r);
        Node ansl,ansr;
        if(L<=mid)ansl=querySum(lc[o],l,mid,L,R);
        if(R>mid)ansr=querySum(rc[o],mid+1,r,L,R);
        Node ans;
        if(ansl.pre==mid-l+1)ans.pre=ansl.pre+ansr.pre;
        else ans.pre=ansl.pre;
        if(ansr.suf==r-mid)ans.suf=ansr.suf+ansl.suf;
        else ans.suf=ansr.suf;
        ans.sum=max(max(ansl.sum,ansr.sum),ansl.suf+ansr.pre);
        return ans;
    }
}T;
void reverse(int &o0,int &o1,int l,int r,int L,int R){
    if(L<=l&&r<=R){
        swap(o0,o1);
        return;
    }
    T.pushdown(o0,l,r);
    T.pushdown(o1,l,r);
    if(L<=mid)reverse(T.lc[o0],T.lc[o1],l,mid,L,R);
    if(R>mid)reverse(T.rc[o0],T.rc[o1],mid+1,r,L,R);
    T.pushup(o0,l,r);
    T.pushup(o1,l,r);
}
signed main(){
	ios::sync_with_stdio(false);
	cin.tie(0),cout.tie(0);
    cin>>n>>m;
    for(int i=1;i<=n;i++)cin>>a[i];
    T.build(rt1,1,n);
    for(int i=1;i<=n;i++)a[i]=!a[i];
    T.build(rt0,1,n);
    while(m--){
        int op,l,r;
        cin>>op>>l>>r;
        l++,r++;
        if(op==0){
            T.update(rt0,1,n,l,r,1);
            T.update(rt1,1,n,l,r,0);
        }
        if(op==1){
            T.update(rt0,1,n,l,r,0);
            T.update(rt1,1,n,l,r,1);
        }
        if(op==2){
            reverse(rt0,rt1,1,n,l,r);
        }
        if(op==3){
            cout<<T.queryTot(rt1,1,n,l,r)<<"\n";
        }
        if(op==4){
            cout<<T.querySum(rt1,1,n,l,r).sum<<"\n";
        }
    }
	return 0;
}
就是动态开点,0,1各开一棵分别记录各个数据,遇到翻转直接交换对应节点,这样完全不用顾忌标记下传的问题(因为只有一个标记了),而且跑得也不慢,调代码成本大幅降低,几乎没法写错,感觉对于调代码能力弱的人(比如我)相对友好。感觉可以写篇题解?反正我懒得写了

回复

6 条回复,欢迎继续交流。

正在加载回复...