P2572 [SCOI2010] 序列操作 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
思路不是很难,码量很大,调试难度高,一个bug找一天(bushi
稍微难一些的就是求[l,r] 区间内最多有多少个连续的 1,可以分别维护一段区间左端,中间,右端有多少个连续的1和0来实现。同时要注意的点是赋0和赋1标记可以覆盖取反标记,而取反标记不能覆盖赋0和赋1标记,而且取反标记更改时要^=1
具体看代码注释
#include<bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define INF_L 0x3f3f3f3f3f3f3f3fLL
#define NOTLE ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
#define endl '\n'
#define T int TT;cin >> TT;while (TT--)
#define lint long long
#define PII pair<int,int>
#define PLL pair<long long,long long>
#define pb push_back
#define eb emplace_back
int a[100010];
int n,m;
struct node{
int l,r,sum;
int sw,t0,t1; //sw取反标记,t0赋0标记,t1赋1标记
int ll1,lm1,lr1,ll0,lm0,lr0;
//ll1维护区间左端连续1的长度
//lm1维护区间中间最长连续1的长度
//lr1维护区间右端连续1的长度
}tree[400010],node0;
void pushup(int p){
tree[p].sum=tree[p<<1].sum+tree[p<<1|1].sum;
tree[p].ll1=tree[p<<1].ll1;
tree[p].lr1=tree[p<<1|1].lr1;
/*如果左或右端的连续1长度等于区间长度,则需要将另一段要合并的区间的左端或右端
的连续1长度加上*/
if(tree[p<<1].ll1==tree[p<<1].r-tree[p<<1].l+1){
tree[p].ll1+=tree[p<<1|1].ll1;
}
if(tree[p<<1|1].lr1==tree[p<<1|1].r-tree[p<<1|1].l+1){
tree[p].lr1+=tree[p<<1].lr1;
}
tree[p].lm1=max(tree[p<<1].lr1+tree[p<<1|1].ll1,max(tree[p<<1].lm1,tree[p<<1|1].lm1));
tree[p].ll0=tree[p<<1].ll0;
tree[p].lr0=tree[p<<1|1].lr0;
if(tree[p<<1].ll0==tree[p<<1].r-tree[p<<1].l+1){
tree[p].ll0+=tree[p<<1|1].ll0;
}
if(tree[p<<1|1].lr0==tree[p<<1|1].r-tree[p<<1|1].l+1){
tree[p].lr0+=tree[p<<1].lr0;
}
tree[p].lm0=max(tree[p<<1].lr0+tree[p<<1|1].ll0,max(tree[p<<1].lm0,tree[p<<1|1].lm0));
}
void pushdown(int p){
if(tree[p].t0){
tree[p<<1].t0=tree[p<<1|1].t0=1;
tree[p<<1].t1=tree[p<<1|1].t1=0;
tree[p<<1].sw=tree[p<<1|1].sw=0;
tree[p<<1].sum=0;
tree[p<<1].ll1=tree[p<<1].lm1=tree[p<<1].lr1=0;
tree[p<<1].ll0=tree[p<<1].lm0=tree[p<<1].lr0=tree[p<<1].r-tree[p<<1].l+1;
tree[p<<1|1].sum=0;
tree[p<<1|1].ll1=tree[p<<1|1].lm1=tree[p<<1|1].lr1=0;
tree[p<<1|1].ll0=tree[p<<1|1].lm0=tree[p<<1|1].lr0=tree[p<<1|1].r-tree[p<<1|1].l+1;
}
if(tree[p].t1){
tree[p<<1].t0=tree[p<<1|1].t0=0;
tree[p<<1].t1=tree[p<<1|1].t1=1;
tree[p<<1].sw=tree[p<<1|1].sw=0;
tree[p<<1].sum=tree[p<<1].r-tree[p<<1].l+1;
tree[p<<1].ll1=tree[p<<1].lm1=tree[p<<1].lr1=tree[p<<1].r-tree[p<<1].l+1;
tree[p<<1].ll0=tree[p<<1].lm0=tree[p<<1].lr0=0;
tree[p<<1|1].sum=tree[p<<1|1].r-tree[p<<1|1].l+1;
tree[p<<1|1].ll1=tree[p<<1|1].lm1=tree[p<<1|1].lr1=tree[p<<1|1].r-tree[p<<1|1].l+1;
tree[p<<1|1].ll0=tree[p<<1|1].lm0=tree[p<<1|1].lr0=0;
}
if(tree[p].sw){
tree[p<<1].sw^=1;
tree[p<<1|1].sw^=1;
tree[p<<1].sum=tree[p<<1].r-tree[p<<1].l+1-tree[p<<1].sum;
swap(tree[p<<1].ll1,tree[p<<1].ll0);
swap(tree[p<<1].lm1,tree[p<<1].lm0);
swap(tree[p<<1].lr1,tree[p<<1].lr0);
tree[p<<1|1].sum=tree[p<<1|1].r-tree[p<<1|1].l+1-tree[p<<1|1].sum;
swap(tree[p<<1|1].ll1,tree[p<<1|1].ll0);
swap(tree[p<<1|1].lm1,tree[p<<1|1].lm0);
swap(tree[p<<1|1].lr1,tree[p<<1|1].lr0);
}
tree[p].t0=tree[p].t1=tree[p].sw=0;
}
void build(int l,int r,int p=1){
tree[p].l=l,tree[p].r=r;
tree[p].ll1=tree[p].lm1=tree[p].lr1=tree[p].ll0=tree[p].lm0=tree[p].lr0=0;
tree[p].sw=tree[p].t0=tree[p].t1=0;
if(l==r){
tree[p].sum=a[l];
if(a[l]) tree[p].ll1=tree[p].lm1=tree[p].lr1=1;
else tree[p].ll0=tree[p].lm0=tree[p].lr0=1;
return ;
}
int mid=l+r>>1;
build(l,mid,p<<1);
build(mid+1,r,p<<1|1);
pushup(p);
}
void turn(int l,int r,int t,int p=1){ //赋值
if(l<=tree[p].l && r>=tree[p].r){
if(t==0){
tree[p].t0=1,tree[p].t1=0;
tree[p].sum=0;
tree[p].ll1=tree[p].lm1=tree[p].lr1=0;
tree[p].ll0=tree[p].lm0=tree[p].lr0=tree[p].r-tree[p].l+1;
}
else {
tree[p].t0=0,tree[p].t1=1;
tree[p].sum=tree[p].r-tree[p].l+1;
tree[p].ll1=tree[p].lm1=tree[p].lr1=tree[p].r-tree[p].l+1;
tree[p].ll0=tree[p].lm0=tree[p].lr0=0;
}
tree[p].sw=0;
return ;
}
pushdown(p);
int mid=tree[p].l+tree[p].r>>1;
if(l<=mid) turn(l,r,t,p<<1);
if(r>mid) turn(l,r,t,p<<1|1);
pushup(p);
}
void swc(int l,int r,int p=1){ //取反
if(l<=tree[p].l && r>=tree[p].r){
tree[p].sum=tree[p].r-tree[p].l+1-tree[p].sum;
swap(tree[p].ll1,tree[p].ll0);
swap(tree[p].lm1,tree[p].lm0);
swap(tree[p].lr1,tree[p].lr0);
tree[p].sw^=1;
return ;
}
pushdown(p);
int mid=tree[p].l+tree[p].r>>1;
if(l<=mid) swc(l,r,p<<1);
if(r>mid) swc(l,r,p<<1|1);
pushup(p);
}
int querysum(int l,int r,int p=1){ //询问区间1个数
if(l<=tree[p].l && r>=tree[p].r) return tree[p].sum;
pushdown(p);
int mid=tree[p].l+tree[p].r>>1,sum=0;
if(l<=mid) sum+=querysum(l,r,p<<1);
if(r>mid) sum+=querysum(l,r,p<<1|1);
return sum;
}
node queryl(int l,int r,int p=1){ //询问区间最长连续1
if(l<=tree[p].l && r>=tree[p].r) return tree[p];
pushdown(p);
int mid=tree[p].l+tree[p].r>>1;
node x=node0,lx=node0,rx=node0;
int fl=0,fr=0;
if(l<=mid){lx=queryl(l,r,p<<1); fl=1;}
if(r>mid){rx=queryl(l,r,p<<1|1); fr=1;}
if(fl+fr==2){
x.ll1=lx.ll1;
x.lr1=rx.lr1;
if(lx.ll1==lx.r-lx.l+1){
x.ll1+=rx.ll1;
}
if(rx.lr1==rx.r-rx.l+1){
x.lr1+=lx.lr1;
}
x.lm1=max(lx.lr1+rx.ll1,max(lx.lm1,rx.lm1));
}
else if(fl==0) x=rx;
else if(fr==0) x=lx;
return x;
}
void init(){
node0.ll1=node0.lm1=node0.lr1=node0.ll0=node0.lm0=node0.lr0=0;
node0.sw=node0.t0=node0.t1=0;
}
int main(){
NOTLE;
init();
cin >> n >> m;
for(int i=1;i<=n;i++) cin >> a[i];
build(1,n);
for(int i=1;i<=m;i++){
int opt,l,r;
cin >> opt >> l >> r;
l++,r++;
if(opt==0){
turn(l,r,0);
}
if(opt==1){
turn(l,r,1);
}
if(opt==2){
swc(l,r);
}
if(opt==3){
cout << querysum(l,r) << endl;
}
if(opt==4){
node x=queryl(l,r);
cout << max(max(x.ll1,x.lr1),x.lm1) << endl;
}
}
return 0;
}
此题还有一种解法是珂朵莉树,但只能过随机的数据,无法通过洛谷上已经针对过的数据
#include<bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define INF_L 0x3f3f3f3f3f3f3f3fLL
#define NOTLE ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
#define endl '\n'
#define T int TT;cin >> TT;while (TT--)
#define lint long long
#define PII pair<int,int>
#define PLL pair<long long,long long>
#define S_IT set<Node>::iterator
#define pb push_back
#define eb emplace_back
#define MAXN 100002
typedef int type;
struct Node{
unsigned int l;
unsigned int r;
mutable type data;
Node(unsigned int a, unsigned int b = 0, type c = 0);
bool operator <(const Node &a) const{return l < a.l;}
};
Node::Node(unsigned int a, unsigned int b, type c){l = a; r = b; data = c;}
set<Node> s;
S_IT split(unsigned int pos){
S_IT it = s.lower_bound(Node(pos));
if (it != s.end() && it->l == pos) return it;
--it;
unsigned int l = it->l, r = it->r;
type data = it->data;
s.erase(it);
s.insert(Node(l, pos - 1, data));
return s.insert(Node(pos, r, data)).first;
}
void swc(int l,int r,int val){
S_IT it2 = split(r + 1), it1 = split(l);
s.erase(it1, it2);
s.insert(Node(l, r, val));
return;
}
void rev(int l,int r){
S_IT it2 = split(r + 1), it1 = split(l);
for (; it1 != it2; ++it1)
it1->data ^= 1;
}
int sum(int l,int r){
S_IT it2 = split(r + 1), it1 = split(l);
int res=0;
for (; it1 != it2; ++it1)
if(it1->data) res+=(it1->r)-(it1->l)+1;
return res;
}
int con(int l,int r){
int res=0,temp=0;
S_IT it2 = split(r + 1), it1 = split(l);
for (; it1 != it2; ++it1){
if (it1->data){
temp+=(it1->r)-(it1->l)+1;
}
else{
res=max(res,temp);
temp=0;
}
}
return max(res, temp);
}
int main(){
NOTLE;
int n, m;
cin >> n >> m;
for (int i = 0; i < n; ++i){
int temp;
cin >> temp;
s.insert(Node(i, i, temp));
}
s.insert(Node(n, n, 0));
while(m--){
int op,a,b;
cin >> op >> a >> b;
if (op==0) swc(a, b, 0);
if (op==1) swc(a, b, 1);
if (op==2) rev(a, b);
if (op==3) cout << sum(a, b) << endl;
if (op==4) cout << con(a, b) << endl;
}
return 0;
}