hdu 3379 Sequence operation(成段更新,区间合并)

http://acm.hdu.edu.cn/showproblem.php?pid=3397

线段树很好的题。涉及到的知识点:lazy操作处理异或操作和置01,区间合并。

有五种操作:

0 a b 将[a,b]变为0

1 a b 将[a,b]变为1

2 a b 将[a,b]取反

3 a b 输出[a,b]的1的个数

4 a b 输出[a,b]内最长的连续1的个数

对区间的操作与poj 3225类似。置01与取反是互斥的,一段区间上只能有一个标记,discuss里面也说了取反的时候若递归到区间全为0或1的时候再取反违背了线段树的本质。因此对于这两个操作设置一个变量lazy,它的取值有-1,0,1,2,-1表示没有操作,0和1表示被0或1覆盖,2表示区间取反。因为两次取反后相当于没取,lazy标记在这里起到很大作用,若要对这个区间取反,只需将其lazy置为2,下次再取反时就变为原来的,即置为-1。

询问区间的1的个数时,只需要sum维护区间的和即可。求连续的1的长度时,需要区间合并,又因为有取反操作,同时还要记录区间内连续的0的个数。

#include <stdio.h>
#include <iostream>
#include <map>
#include <set>
#include <list>
#include <stack>
#include <vector>
#include <math.h>
#include <string.h>
#include <queue>
#include <string>
#include <stdlib.h>
#include <algorithm>
//#define LL long long
#define LL __int64
#define eps 1e-12
#define PI acos(-1.0)
using namespace std;
const int INF = 0x3f3f3f3f;
const int maxn = 100010;

/*
节点共有如下信息:
lazy:标记区间中的操作或覆盖情况,
sum:区间的和,
ll[2]表示从左边数连续的0和1的个数,rr[2]表示从右边数连续的0和1的个数,
long0、long1分别表示最长的连续的0和1的长度。
*/
struct node
{
	int l,r;
	int lazy;
	int sum;
	int ll[2],rr[2];
	int long1,long0;
}tree[maxn*4];

int a[maxn];
/*
向上更新,更新父亲节点的和以及ll[],rr[],long0,long1
*/
void push_up(int v)
{
	int l = tree[v].l,r = tree[v].r;
	int ls = v*2,rs = v*2+1;
	int mid = (l+r)>>1;

	tree[v].sum = tree[ls].sum + tree[rs].sum;
	tree[v].ll[0] = tree[ls].ll[0];
	if(tree[ls].sum == 0)
		tree[v].ll[0] += tree[rs].ll[0];
	tree[v].ll[1] = tree[ls].ll[1];
	if(tree[ls].sum == mid-l+1)
		tree[v].ll[1] += tree[rs].ll[1];

	tree[v].rr[0] = tree[rs].rr[0];
	if(tree[rs].sum == 0)
		tree[v].rr[0] += tree[ls].rr[0];
	tree[v].rr[1] = tree[rs].rr[1];
	if(tree[rs].sum == r-mid)
		tree[v].rr[1] += tree[ls].rr[1];

	tree[v].long0 = max(max(tree[ls].long0,tree[rs].long0),tree[ls].rr[0]+tree[rs].ll[0]);
	tree[v].long1 = max(max(tree[ls].long1,tree[rs].long1),tree[ls].rr[1]+tree[rs].ll[1]);
}
/*
向下更新,lazy为0或1时直接覆盖子区间,为2时看子区间是否被完全覆盖,若是就直接取反,否则子节点的lazy取反
*/
void push_down(int v)
{
	if(tree[v].l == tree[v].r || tree[v].lazy == -1)
		return;
	int l = tree[v].l,r = tree[v].r;
	int ls = v*2,rs = v*2+1;
	int mid = (l + r)>>1;
	if(tree[v].lazy == 0)
	{
		tree[ls].lazy = tree[rs].lazy = 0;
		tree[ls].sum = tree[rs].sum = 0;
		tree[ls].long1 = tree[rs].long1 = 0;
		tree[ls].ll[1] = tree[ls].rr[1] = tree[rs].ll[1] = tree[rs].rr[1] = 0;
		tree[ls].ll[0] = tree[ls].rr[0] = tree[ls].long0 = mid-l+1;
		tree[rs].ll[0] = tree[rs].rr[0] = tree[rs].long0 = r-mid;
	}
	else if(tree[v].lazy == 1)
	{
		tree[ls].lazy = tree[rs].lazy = 1;
		tree[ls].sum = mid-l+1;
		tree[rs].sum = r-mid;
		tree[ls].long0 = tree[rs].long0 = 0;
		tree[ls].ll[0] = tree[ls].rr[0] = tree[rs].ll[0] = tree[rs].rr[0] = 0;
		tree[ls].ll[1] = tree[ls].rr[1] = tree[ls].long1 = mid-l+1;
		tree[rs].ll[1] = tree[rs].rr[1] = tree[rs].long1 = r-mid;
	}
	else if(tree[v].lazy == 2)
	{
		if(tree[ls].lazy == -1 || tree[ls].lazy == 2)
		{
			tree[ls].lazy = 1-tree[ls].lazy;
			tree[ls].sum = mid-l+1-tree[ls].sum;
			swap(tree[ls].long0,tree[ls].long1);
			swap(tree[ls].ll[0],tree[ls].ll[1]);
			swap(tree[ls].rr[0],tree[ls].rr[1]);
		}
		else if(tree[ls].lazy == 1)
		{
			tree[ls].lazy = 0;
			tree[ls].sum = 0;
			tree[ls].long0 = tree[ls].ll[0] = tree[ls].rr[0] = mid-l+1;
			tree[ls].long1 = tree[ls].ll[1] = tree[ls].rr[1] = 0;
		}
		else if(tree[ls].lazy == 0)
		{
			tree[ls].lazy = 1;
			tree[ls].sum = mid-l+1;
			tree[ls].long0 = tree[ls].ll[0] = tree[ls].rr[0] = 0;
			tree[ls].long1 = tree[ls].ll[1] = tree[ls].rr[1] = mid-l+1;
		}

		if(tree[rs].lazy == -1 || tree[rs].lazy == 2)
		{
			tree[rs].lazy = 1-tree[rs].lazy;
			tree[rs].sum = r-mid-tree[rs].sum;
			swap(tree[rs].long0,tree[rs].long1);
			swap(tree[rs].ll[0],tree[rs].ll[1]);
			swap(tree[rs].rr[0],tree[rs].rr[1]);
		}
		else if(tree[rs].lazy == 1)
		{
			tree[rs].lazy = 0;
			tree[rs].sum = 0;
			tree[rs].long0 = tree[rs].ll[0] = tree[rs].rr[0] = r-mid;
			tree[rs].long1 = tree[rs].ll[1] = tree[rs].rr[1] = 0;
		}
		else if(tree[rs].lazy == 0)
		{
			tree[rs].lazy = 1;
			tree[rs].sum = r-mid;
			tree[rs].long0 = tree[rs].ll[0] = tree[rs].rr[0] = 0;
			tree[rs].long1 = tree[rs].ll[1] = tree[rs].rr[1] = r-mid;
		}

	}
	tree[v].lazy = -1;
}

void build(int v, int l, int r)
{
	tree[v].l = l;
	tree[v].r = r;
	tree[v].lazy = -1;
	tree[v].sum = 0;
	tree[v].ll[0] = tree[v].rr[0] = tree[v].long0 = 0;
	tree[v].ll[1] = tree[v].rr[1] = tree[v].long1 = 0;
	if(l == r)
	{
		tree[v].sum = a[l];
		if(a[l] == 0)
			tree[v].ll[0] = tree[v].rr[0] = tree[v].long0 = 1;
		else
			tree[v].ll[1] = tree[v].rr[1] = tree[v].long1 = 1;
		return;
	}
	int mid = (l+r)>>1;
	build(v*2,l,mid);
	build(v*2+1,mid+1,r);
	push_up(v);
}

void update(int v, int l, int r, int op)
{
	if(tree[v].l == l && tree[v].r == r)
	{
		if(op == 0)
		{
			tree[v].lazy = tree[v].sum = 0;
			tree[v].ll[0] = tree[v].rr[0] = tree[v].long0 = tree[v].r - tree[v].l + 1;
			tree[v].ll[1] = tree[v].rr[1] = tree[v].long1 = 0;
		}
		else if(op == 1)
		{
			tree[v].lazy = 1;
			tree[v].sum = tree[v].r - tree[v].l + 1;
			tree[v].ll[1] = tree[v].rr[1] = tree[v].long1 = tree[v].r - tree[v].l + 1;
			tree[v].ll[0] = tree[v].rr[0] = tree[v].long0 = 0;
		}
		else if(op == 2)
		{
			if(tree[v].lazy == 0)
			{
				tree[v].lazy = 1;
				tree[v].sum = tree[v].r - tree[v].l + 1;
				tree[v].ll[1] = tree[v].rr[1] = tree[v].long1 = tree[v].r-tree[v].l+1;
				tree[v].ll[0] = tree[v].rr[0] = tree[v].long0 = 0;
			}
			else if(tree[v].lazy == 1)
			{
				tree[v].lazy = tree[v].sum = 0;
				tree[v].ll[1] = tree[v].rr[1] = tree[v].long1 = 0;
				tree[v].ll[0] = tree[v].rr[0] = tree[v].long0 = tree[v].r-tree[v].l+1;
			}
			else if(tree[v].lazy == -1 || tree[v].lazy == 2)
			{
				tree[v].lazy = 1-tree[v].lazy;
				tree[v].sum = tree[v].r-tree[v].l+1-tree[v].sum;
				swap(tree[v].long0,tree[v].long1);
				swap(tree[v].ll[0],tree[v].ll[1]);
				swap(tree[v].rr[0],tree[v].rr[1]);
			}
		}
		return;
	}
	push_down(v);
	int mid = (tree[v].l + tree[v].r) >> 1;
	if(r <= mid)
		update(v*2,l,r,op);
	else if(l > mid)
		update(v*2+1,l,r,op);
	else
	{
		update(v*2,l,mid,op);
		update(v*2+1,mid+1,r,op);
	}
	push_up(v);
}

int query(int v, int l, int r,int op)
{
	if(tree[v].l == l && tree[v].r == r)
	{
		if(op == 3)
			return tree[v].sum;
		else
			return tree[v].long1;
	}
	push_down(v);
	int mid = (tree[v].l + tree[v].r) >> 1;
	if(r <= mid)
		return query(v*2,l,r,op);
	else if(l > mid)
		return query(v*2+1,l,r,op);
	else
	{
		if(op == 3)
			return query(v*2,l,mid,op) + query(v*2+1,mid+1,r,op);
		else
		{
			//求区间[l,r]中最长的连续是1的长度。
			int tmp = min(tree[v*2].rr[1],mid-l+1) + min(tree[v*2+1].ll[1],r-mid);
			return max(tmp,max(query(v*2,l,mid,op),query(v*2+1,mid+1,r,op)));
		}
	}
}

int main()
{
	int test;
	int n,m;
	int op,l,r;

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

hdu 3379 Sequence operation(成段更新,区间合并)

时间: 2024-10-24 14:51:21

hdu 3379 Sequence operation(成段更新,区间合并)的相关文章

HDU 3397 Sequence operation(线段树&#183;成段更新&#183;区间合并&#183;混合操作)

题意  给你一个只有0, 1的数组  有这些操作 0. 将[a, b]区间的所有数都改为0 1. 将[a, b]区间的所有数都改为1 2. 将[a, b]区间的所有数都取反 即与1异或 3. 输出区间[a, b]中1的个数  即所有数的和 4. 输出区间[a, b]中最大连续1的长度 对于所有的3, 4操作输出对应的答案 单个的操作都很简单  但搞在一起就有点恶心了  还好数组里的数只有0和1 线段树维护9个值 对应区间0, 1的最大长度len[i]  对应区间左端点为起点的最大0, 1长度ll

(简单) HDU 3397 Sequence operation,线段树+区间合并。

Problem Description lxhgww got a sequence contains n characters which are all '0's or '1's. We have five operations here: Change operations: 0 a b change all characters into '0's in [a , b] 1 a b change all characters into '1's in [a , b] 2 a b chang

poj 3669 线段树成段更新+区间合并

添加 lsum[ ] , rsum[ ] , msum[ ] 来记录从左到右的区间,从右到左的区间和最大的区间: #include<stdio.h> #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define maxn 50005 int rsum[maxn<<2],lsum[maxn<<2],msum[maxn<<2];//msum[]维护区间1…N中的最大连续区间长度 int

POJ训练计划2777_Count Color(线段树/成段更新/区间染色)

解题报告 题意: 对线段染色,询问线段区间的颜色种数. 思路: 本来直接在线段树上染色,lz标记颜色.每次查询的话访问线段树,求出颜色种数.结果超时了,最坏的情况下,染色可以染到叶子节点. 换成存下区间的颜色种数,这样每次查询就不用找到叶子节点了,用按位或来处理颜色种数. #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace

NYOJ 1068 ST(线段树之 成段更新+区间求和)

ST 时间限制:1000 ms  |  内存限制:65535 KB 难度:1 描述 "麻雀"lengdan用随机数生成了后台数据,但是笨笨的他被妹纸的问题给难住了... 已知lengdan生成了N(1=<N<=10005)个随机整数,妹子对这些数可能有以下几种操作或询问: 1,A a b c 表示给区间a到b内每个数都加上c: 2,S a b  表示输出区间a到b内的和: 3,Q a b 表示区间a到b内的奇数的个数: 为了使妹纸不口渴,所以我们决定妹纸的询问次数少一点,即

HDU 3308 LCIS (线段树&#183;单点更新&#183;区间合并)

题意  给你一个数组  有更新值和查询两种操作  对于每次查询  输出对应区间的最长连续递增子序列的长度 基础的线段树区间合并  线段树维护三个值  对应区间的LCIS长度(lcis)  对应区间以左端点为起点的LCIS长度(lle)  对应区间以右端点为终点的LCIS长度(lri)  然后用val存储数组对应位置的值  当val[mid + 1] > val[mid] 的时候就要进行区间合并操作了 #include <cstdio> #include <algorithm>

poj 2777 Count Color (成段更新+区间求和)

Count Color Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 36646   Accepted: 11053 Description Chosen Problem Solving and Program design as an optional course, you are required to solve all kinds of problems. Here, we get a new problem.

B - 卿学姐与基本法 (离散化+成段更新+区间求和)

卿学姐与基本法 Time Limit: 2000/1000MS (Java/Others)     Memory Limit: 65535/65535KB (Java/Others) Submit Status “做专题也要按照基本法” 离开了诡异的村庄,卿学姐来到了威廉·圣·乱七八糟王国,这里的国王咸鱼王是个智障. 国家涣散,盗贼四起,民不聊生. 见到这样的景象,卿学姐不禁潸然泪下,“悠悠苍天,奈何苦了苍生”. 自幼学习基本法的卿学姐决定向整个国家普及基本法,改善国家法度. 在这个国家总共有N

hdu 1698 线段树 成段更新

题意:一段钩子,每个钩子的值为1,有若干更新,每次跟新某段的值,若干查询某段的和 基础题了 1 #include<cstdio> 2 #include<iostream> 3 #include<algorithm> 4 #include<cstring> 5 #include<cmath> 6 #include<queue> 7 #include<map> 8 using namespace std; 9 #define