练习41,[SCOI2010] 序列操作【线段树】

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;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ILECY

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值