首页 > 其他分享 >毒瘤线段树

毒瘤线段树

时间:2022-10-26 14:36:17浏览次数:58  
标签:return rs int 线段 mid 毒瘤 序列 query

[SCOI2010] 序列操作

题目描述

lxhgww 最近收到了一个 \(01\) 序列,序列里面包含了 \(n\) 个数,下标从 \(0\) 开始。这些数要么是 \(0\),要么是 \(1\),现在对于这个序列有五种变换操作和询问操作:

  • 0 l r 把 \([l, r]\) 区间内的所有数全变成 \(0\)

  • 1 l r 把 \([l, r]\) 区间内的所有数全变成 \(1\)

  • 2 l r 把 \([l,r]\) 区间内的所有数全部取反,也就是说把所有的 \(0\) 变成 \(1\),把所有的 \(1\) 变成 \(0\)

  • 3 l r 询问 \([l, r]\) 区间内总共有多少个 \(1\)

  • 4 l r 询问 \([l, r]\) 区间内最多有多少个连续的 \(1\)

对于每一种询问操作,lxhgww 都需要给出回答,聪明的程序员们,你们能帮助他吗?

输入格式

第一行两个正整数 \(n,m\),表示序列长度与操作个数。
第二行包括 \(n\) 个数,表示序列的初始状态。
接下来 \(m\) 行,每行三个整数,表示一次操作。

输出格式

对于每一个询问操作,输出一行一个数,表示其对应的答案。

样例 #1

样例输入 #1

10 10
0 0 0 1 1 0 1 0 1 1
1 0 2
3 0 5
2 2 2
4 0 4
0 3 6
2 3 7
4 2 8
1 0 5
0 5 6
3 3 9

样例输出 #1

5
2
6
5

提示

【数据范围】
对于 \(30\%\) 的数据,\(1\le n,m \le 1000\);
对于\(100\%\) 的数据,\(1\le n,m \le 10^5\)。


二百行!
就为了维护线段树信息无脑加信息就得了
但是变量多了很容易乱
细节出错很要命
写线段树之前要把每个信息维护的细节想清楚写下来再下手写
边写边想很多细节会忘掉

#include<bits/stdc++.h>
using namespace std;
const int N = 2e5+9;
int n,m;
#define ls p<<1
#define rs p<<1|1
int a[N];

struct tree
{
	int l,r,sum,ans0,ans,pre1,pre0,sub1,sub0,add0,add1,add;
	tree()
	{
		l = r = sum = ans0 = pre1 = sub1 = add0 = add1 = add = pre0 = sub0 = ans = 0;
	}
	
	void col0()
	{
		add0 = 1;
		sum = pre1 = sub1 = add1 = add = ans = 0;
		ans0 = pre0 = sub0 = (r-l+1);
	}
	
	void col1()
	{
		add1 = 1;
		sum = pre1 = sub1 =  ans = (r-l+1);
		ans0 = pre0 = sub0 = add0 = add = 0;
	}
	
	void col()
	{
		add ^= 1;
		sum = (r-l+1-sum);
		swap(add0,add1);
		swap(pre1,pre0);
		swap(sub1,sub0);
		swap(ans,ans0);
	}
	
	#define l(x) t[x].l 
	#define r(x) t[x].r
	#define sum(x) t[x].sum 
	#define ans(x) t[x].ans
	#define ans0(x) t[x].ans0 
	#define pre1(x) t[x].pre1 
	#define pre0(x) t[x].pre0 
	#define sub1(x) t[x].sub1 
	#define sub0(x) t[x].sub0 
	#define add1(x) t[x].add1 
	#define add0(x) t[x].add0 
	#define add(x) t[x].add 
}t[N<<1];

tree operator +(const tree &l,const tree &r)
{
	tree p;
	p.add = p.add0 = p.add1 = 0;
	p.l = l.l,
	p.r = r.r;
	p.sum = l.sum+r.sum;
	if(l.pre1 == (l.r-l.l+1))p.pre1 = (l.r-l.l+1) + r.pre1;
	else p.pre1 = l.pre1;
	if(r.sub1 == (r.r-r.l+1))p.sub1 = l.sub1 + (r.r-r.l+1);
	else p.sub1 = r.sub1;
	
	if(l.pre0 == (l.r-l.l+1))p.pre0 = (l.r-l.l+1) + r.pre0;
	else p.pre0 = l.pre0;
	if(r.sub0 == (r.r-r.l+1))p.sub0 = l.sub0 + (r.r-r.l+1);
	else p.sub0 = r.sub0;
	
	p.ans = max(l.ans,r.ans);
	p.ans = max(p.ans,l.sub1+r.pre1);
	p.ans0 = max(l.ans0,r.ans0);
	p.ans0 = max(p.ans0,l.sub0+r.pre0);
	return p;
}

void pushup(int p)
{
	t[p] = t[ls] + t[rs];
}

void pushdown(int p)
{
	if(add(p))
	{
		t[ls].col();
		t[rs].col();
		add(p) = 0;
	}
	if(add0(p))
	{
		t[ls].col0();
		t[rs].col0();
		add0(p) = 0;
	}
	else if(add1(p))
	{
		t[ls].col1();
		t[rs].col1();
		add1(p) = 0;
	}
}

void build(int p,int l,int r)
{
	if(l == r)
	{
		l(p) = r(p) = l;
		
		if(a[l])t[p].col1();
		else t[p].col0();
		
		return;
	}
	int mid = (l+r)>>1;
	build(ls,l,mid);
	build(rs,mid+1,r);
	pushup(p);
}

void modify0(int p,int l,int r)
{
	if(l <= l(p) && r >= r(p))
	{
		t[p].col0();
		return;
	}
	pushdown(p);
	
	int mid = (l(p)+r(p))>>1;
	if(l <= mid)modify0(ls,l,r);
	if(r > mid)modify0(rs,l,r);
	
	pushup(p);
}

void modify1(int p,int l,int r)
{
	if(l <= l(p) && r >= r(p))
	{
		t[p].col1();
		return;
	}
	
	pushdown(p);
	
	int mid = (l(p)+r(p))>>1;
	if(l <= mid)modify1(ls,l,r);
	if(r > mid)modify1(rs,l,r);
	
	pushup(p);
}

void modify(int p,int l,int r)
{
	if(l <= l(p) && r >= r(p))
	{
		t[p].col();
		return;
	}
	
	pushdown(p);
	
	int mid = (l(p)+r(p))>>1;
	if(l <= mid)modify(ls,l,r);
	if(r > mid)modify(rs,l,r);
	
	pushup(p);
}

tree query(int p,int l,int r)
{	
	if(l <= l(p) && r >= r(p))return t[p];
	
	pushdown(p);
	
	int mid = (l(p)+r(p))>>1;
	if(r <= mid)return query(ls,l,r);
	else if(l > mid)return query(rs,l,r);
	else return query(ls,l,r) + query(rs,l,r);
}

int main()
{
	scanf("%d%d",&n,&m);
	for(int i = 1;i <= n;i++)scanf("%d",&a[i]);
	build(1,1,n);
	while(m--)
	{
		int op,l,r;
		scanf("%d%d%d",&op,&l,&r);
		l++,r++;
		if(op == 0)modify0(1,l,r);
		else if(op == 1)modify1(1,l,r);
		else if(op == 2)modify(1,l,r);
		else if(op == 3)printf("%d\n",query(1,l,r).sum);
		else printf("%d\n",query(1,l,r).ans);
	}
	return 0;
}

标签:return,rs,int,线段,mid,毒瘤,序列,query
From: https://www.cnblogs.com/AC7-/p/16828253.html

相关文章

  • 数据结构:线段树基础详解
    1.简介线段树,顾名思义,就是由线段构成的树,是一个较为优秀的数据结构,它将一个区间划分成一些单元区间,每个单元区间对应线段树中的一个叶结点,通常用于解决区间类的问题,在各大......
  • fzu_noip 1039(盖楼-线段树)
    盖楼时限:1s内存:32M★问题描述:S举办了一场盖楼比赛,有n位选手参赛,将这n位选手编号为1到n。比赛刚开始时第i位选手的房子的初始高度为Ai,每过一天该选手的房子高度增加Bi。S想......
  • BZOJ 3110([Zjoi2013]K大数查询-区间第k大[段修改,在线]-树状数组套函数式线段树)
    3110:[Zjoi2013]K大数查询TimeLimit: 20Sec  MemoryLimit: 512MBSubmit: 418  Solved: 235[​​Submit​​][​​Status​​][​​Discuss​​]Des......
  • 动态开点线段树
    普通的线段树是满二叉树,大小为\(4n\),在有些题目中无法满足空间限制,此时就需要用动态开点线段树去解决这个问题0x01口胡开始我们是如何表示一个普通线段树的?左儿子:......
  • BZOJ 4373(算术天才⑨与等差数列-线段树+hash)
    Description算术天才⑨非常喜欢和等差数列玩耍。有一天,他给了你一个长度为n的序列,其中第i个数为a[i]。他想考考你,每次他会给出询问l,r,k,问区间[l,r]内的数从小到大排序......
  • CF438D(The Child and Sequence-线段树mod x)
    维护一个区间的和,支持单点修改,区间modx考虑a>x,时,amodx<a/2,否则a=x所以暴力维护就行了#include<iostream>#include<cmath>#include<algorithm>#include<cstdio>#inclu......
  • 线段树优化建图 (CF786B、SNOI2017炸弹)
    先来看板子题:CF786B可以发现,如果对着区间内的每一个点都建一条边,然后跑最短路,我们无论是在空间还是时间复杂度上都是过不去的。因此,我们请出老朋友线段树。参考上图。......
  • 线段树
    线段树是一种数据结构,大概长成这个样子:而线段树的每个节点都包含了它的范围以及它里面的数字,每个节点最多有2个子节点,而节点还包含一个附加信息(例如最大值,求和),而现在我们......
  • P6492 STEP(线段树维护左右区间pushup)
    题目链接题目描述:给定一个长度为\(~\)n\(~\)的字符序列\(~\)a,初始时序列中全部都是字符\(~\)L。有\(~\)q\(~\)次修改,每次给定一个\(~\)x,做出如下变化:\(~~\)1.a\(_......
  • 线段树 & 题目
    首先说下我写的线段树吧。我是按照线段树【完全版】那个人的写法来写的,因为网上大多数题解都是按照他的写法来写。确实比较飘逸,所以就借用了。节点大小是maxn是4倍,准确来说......