2151: 集训难度(包含两种操作的线段树)

2151: 集训难度

Submit Page    Summary    Time Limit: 1 Sec     Memory Limit: 512 Mb     Submitted: 55     Solved: 12    


Description

小L正在组织acm暑假集训,但众所周知,暑假集训的萌新中有OI神犇,也有暑假才开始学算法的萌新,如果统一集训的难度,无法很好地让萌新们得到训练,所以小L想了一个办法,根据每次测试的情况,改变萌新们的集训难度。现在将萌新们编号为1到n,最初萌新们的集训难度为v0,测试后有两种操作,第一种是某一区间的萌新的集训难度同时提高,另一种是将某一段区间的萌新的集训难度变为同一个数,同时,Wells希望在某次调整难度之后,知道某一段区间的萌新的集训难度之和,由于小L比较鶸,他并不知道如何快速解决这个问题,你能帮帮他嘛?

 

Input

第一行三个数n,m,v0 表示有n名萌新和m次调整,初始时全部萌新的集训难度都为v0

第2~m+1行 每行三个数或四个数

0 x y v 表示把 [x,y]区间内的萌新的集训难度都增加v

1 x y v 表示把 [x,y]区间内的萌新的集训难度都变为v

2 x y表示询问[x,y]区间内萌新的集训难度之和

0<n,m<=10^5, |v|<=10^5

Output

每个询问一行,输出答案

Sample Input

3 5 0
0 1 3 1
1 2 3 2
2 1 1  
2 2 2
2 2 3

Sample Output

1
2
4

Hint

Source

某场noip模拟题

Author

lfw

题目看起来不难,根本模板题一样的(但是我WA了一个早上),就是简单地写一个线段树,他同时具备染色操作和增加某个数的操作。

思路:

设置两个tag,tag1表示当前区间要全部加上tag1, tag2表示当前区间全被染成tag2,传递tag1的时候,如果tag1存在,那么如果子节点的tag2存在,那么直接往tag2上加,如果没有,就往子节点的tag1上加,传tag2的时候,子节点的tag1直接就清掉,然后tag2就继承下来。

AC代码:

//假如加上一个变化操作 ,就把加法操作的tag清空
//如何下传被清空的tag标记?
//难以实现 
//那么选择直接把tag1加到tag2上 ? 
#include<algorithm>
#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<vector>
#include<stack>
#include<cmath>
#include<queue>
#include<set>
#include<map>
#define md(l,r) (l+r)>>1
#define rson(x) x<<1|1
#define lson(x) x<<1
#define endl '\n'
#define sc(x) scanf("%d",&x)

using namespace std;
typedef long long LL;
const int size=1e5+5;
const int inf=0x3f3f3f3f;
struct node{
	int l,r;
	LL sum,tag;
	LL tag2;
	bool flag ;
}tree[size<<2];
void build(int k,int l,int r,int v)
{
	tree[k].l=l,tree[k].r=r;
	if(l==r)
	{
		tree[k].sum=v;
		tree[k].tag=0;
		tree[k].tag2=inf;
		tree[k].flag=0;
		return ;
	}
	int mid=md(l,r);
	build(rson(k),mid+1,r,v);
	build(lson(k),l,mid,v);
	tree[k].sum=tree[lson(k)].sum+tree[rson(k)].sum;
	tree[k].tag=0;
	tree[k].tag2=inf;
	tree[k].flag=0;
}
void change(int k)
{
	if(tree[k].l!=tree[k].r)
	{
		int ls=lson(k),rs=rson(k);
		tree[rs].sum+=(tree[rs].r-tree[rs].l+1)*tree[k].tag;
		tree[ls].sum+=(tree[ls].r-tree[ls].l+1)*tree[k].tag;
		if(tree[ls].tag2==inf)
		tree[ls].tag+=tree[k].tag;
		else tree[ls].tag2+=tree[k].tag;
		if(tree[rs].tag2==inf)
		tree[rs].tag+=tree[k].tag;
		else tree[rs].tag2+=tree[k].tag;
		
		
		tree[ls].flag=1;
		tree[rs].flag=1;
	}
	tree[k].tag=0;
	tree[k].flag=0;
}
void change2(int k)
{
	if(tree[k].l!=tree[k].r)
	{
		int ls=lson(k),rs=rson(k);
		tree[ls].sum=tree[k].tag2*(tree[ls].r-tree[ls].l+1);
		tree[rs].sum=(tree[rs].r-tree[rs].l+1)*tree[k].tag2;
		tree[ls].tag2=tree[k].tag2;
		tree[rs].tag2=tree[k].tag2;
		tree[ls].tag=0;
		tree[rs].tag=0;
	}
	tree[k].tag2=inf;
}
void add2(int k,int l,int r,LL x)
{
	if(tree[k].flag) change(k);
	if(tree[k].tag2!=inf) change2(k);
	if(tree[k].l==l&&tree[k].r==r)
	{
		tree[k].sum=x*(r-l+1);
		tree[k].tag2=x;
		tree[k].tag=0;
		return ;
	}
	int mid=md(tree[k].l,tree[k].r);
	if(l>=mid+1) add2(rson(k),l,r,x);
	else if(r<=mid) add2(lson(k),l,r,x);
	else add2(lson(k),l,mid,x),add2(rson(k),mid+1,r,x);
	tree[k].sum=tree[lson(k)].sum+tree[rson(k)].sum;
}
void add(int k,int l,int r,LL x)
{
	if(tree[k].flag) change(k);
	if(tree[k].tag2!=inf) change2(k);
	tree[k].sum+=x*(r-l+1);
	if(l==tree[k].l&&r==tree[k].r)
	{
		tree[k].tag+=x;
		tree[k].flag=1;
		return ;
	}
	int mid=md(tree[k].l,tree[k].r);
	if(l>=mid+1)
	{
		add(rson(k),l,r,x);
	}
	else if(r<=mid)
	{
		add(lson(k),l,r,x);
	}
	else
	{
		add(lson(k),l,mid,x),add(rson(k),mid+1,r,x);
	}
	tree[k].sum=tree[lson(k)].sum+tree[rson(k)].sum;
}
LL query(int k,int l,int r)
{
	LL ans=0;
	if(tree[k].flag) change(k);
	if(tree[k].tag2!=inf) change2(k);
	if(l==tree[k].l&&r==tree[k].r)
	{
		return tree[k].sum;
	}	
	int mid=md(tree[k].l,tree[k].r);
	if(l>=mid+1)
	{
		ans=query(rson(k),l,r);
	} 
	else if(r<=mid)
	{
		ans=query(lson(k),l,r);
	}
	else
	{
		ans=query(lson(k),l,mid)+query(rson(k),mid+1,r);
	}
	return ans;
}
int main()
{
	int n,m,v0;
	while(~scanf("%d%d%d",&n,&m,&v0))
	{
		build(1,1,n+1,v0);
		while(m--)
		{
			int op;
			scanf("%d",&op);
			if(op==0)
			{
				int l,r,v;
				scanf("%d%d%d",&l,&r,&v);
				add(1,l,r,v);
			}
			else if(op==1)
			{
				int l,r,v;
				scanf("%d%d%d",&l,&r,&v);
				add2(1,l,r,v);
			}
			else if(op==2)
			{
				int l,r;
				sc(l),sc(r);
				cout<<query(1,l,r)<<endl;
			}
		}
	}
	
	return 0;
}
/*
4 9 2
0 1 3 2
2 1 1 
1 2 4 2
2 1 1
0 1 4 1
2 1 1
2 2 2
2 3 3
2 4 4
*/

/**********************************************************************
	Problem: 2151
	User: 0908170402
	Language: C++
	Result: AC
	Time:352 ms
	Memory:17648 kb
**********************************************************************/

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值