社区讨论
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 条回复,欢迎继续交流。
正在加载回复...