码迷,mamicode.com
首页 > 其他好文 > 详细

Weed「线段树」

时间:2020-10-21 21:18:58      阅读:24      评论:0      收藏:0      [点我收藏+]

标签:queue   line   freopen   http   html   cut   shu   names   stdout   

题目描述

后缀为 contest/140/problem/3

思路分析

  • 考场上的确写了线段树,但是是针对中间那 \(20\) 分打的……
  • 其实这道题的思想和线段树维护单调栈非常类似,(如果不明白建议去看一下这篇博客陶陶摘苹果)都是左右儿子之间互相和谐,只不过维护单调栈时左右儿子互相和谐的原因是因为要满足单调性,而这道题已经给出了和谐的条件
  • 同样的,这题的难点也在于 pushup 合并。为了方便维护和合并区间,我们需要在线段树中记录三个值:\(cnt\)—添加的层数,\(val\)—添加的高度,\(cut\)—需要删除的层数。
    这样在 pushup 时,分三种情况讨论:
    1. 右儿子将左儿子区间内的层数全部删除完,这时候只剩下右儿子
    2. 右儿子没有删除操作,这时候直接讲将左右儿子信息合并即可
    3. 左儿子未被右儿子删除完,这时候需要用一个函数来判断左儿子还剩下多少
  • 定义这个函数为 find,用来进行删除,显然我们要从右儿子开始删除,因为是从右向左删,这时候同样分为三种情况:
    1. 右儿子刚好被删除,直接删就好了
    2. 右儿子没有被删完,继续递归右儿子处理
    3. 右儿子被删完后左儿子也会被删,这时候直接递归左儿子,因为右儿子删没了

\(Code\)

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#define R register
#define N 400010
using namespace std;
inline int read(){
	int x = 0,f = 1;
	char ch = getchar();
	while(ch>‘9‘||ch<‘0‘){if(ch==‘-‘)f=-1;ch=getchar();}
	while(ch>=‘0‘&&ch<=‘9‘){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
}
int m,q,c[N],v[N];
struct Segment_Tree{
	int cnt,val,cut;
}tr[N<<2];
#define ls rt<<1
#define rs rt<<1|1
int find(int rt,int w){//以此对应上面的三种情况
	if(tr[rs].cnt == w)return tr[rt].val - tr[rs].val;
	if(tr[rs].cnt > w)return tr[rt].val - (tr[rs].val - find(rs,w));
	else return find(ls,w+tr[rs].cut-tr[rs].cnt);
}
void pushup(int rt){//同样
	if(tr[rs].cut>=tr[ls].cnt){
		tr[rt].cut = tr[ls].cut + tr[rs].cut - tr[ls].cnt;
		tr[rt].cnt = tr[rs].cnt,tr[rt].val = tr[rs].val;
	}
	else if(!tr[rs].cut){
		tr[rt].cut = tr[ls].cut;
		tr[rt].cnt = tr[ls].cnt + tr[rs].cnt,tr[rt].val = tr[ls].val + tr[rs].val;
	}
	else{
		tr[rt].cut = tr[ls].cut;
		tr[rt].cnt = tr[rs].cnt + tr[ls].cnt - tr[rs].cut;
		tr[rt].val = tr[rs].val + find(ls,tr[rs].cut);
	}
}
void build(int rt,int l,int r){
	if(l==r){
		if(!c[l])tr[rt].cnt = 1,tr[rt].val = v[l],tr[rt].cut = 0;
		else tr[rt].cnt = 0,tr[rt].val = 0,tr[rt].cut = v[l];
		return;
	}
	int mid = (l+r)>>1;
	build(ls,l,mid);
	build(rs,mid+1,r);
	pushup(rt);
}
void modify(int rt,int l,int r,int aim,int flag,int val){
	if(l==r){
		if(!flag)tr[rt].cnt = 1,tr[rt].val = val,tr[rt].cut = 0;
		else tr[rt].cnt = 0,tr[rt].val = 0,tr[rt].cut = val;
		return;
	}
	int mid = (l+r)>>1;
	if(aim<=mid)modify(ls,l,mid,aim,flag,val);
	else modify(rs,mid+1,r,aim,flag,val);
	pushup(rt);
}
int main(){
#if 1
	freopen("weed.in","r",stdin);
	freopen("weed.out","w",stdout);
#endif
	m = read(),q = read();
	for(R int i = 1;i <= m;i++){
		c[i] = read(),v[i] = read();
	}
	build(1,1,m);
	for(R int i = 1;i <= q;i++){
		int x = read(),a = read(),b = read();
		modify(1,1,m,x,a,b);
		printf("%d\n",tr[1].val);
	}
	return 0;
}

Weed「线段树」

标签:queue   line   freopen   http   html   cut   shu   names   stdout   

原文地址:https://www.cnblogs.com/hhhhalo/p/13853049.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!