• Weed「线段树」


    题目描述

    后缀为 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
    ",tr[1].val);
    	}
    	return 0;
    }
    
  • 相关阅读:
    Xcode8 去除系统日志输出
    SVN参考命令
    Xcode模拟网络状态
    iOS 图片拉伸
    iOS进阶
    label中添加图片
    Cookie的格式及组成
    java数据类型总结
    Hibernate一级缓存与二级缓存的区别
    mysql连接jdbc查询代码
  • 原文地址:https://www.cnblogs.com/hhhhalo/p/13853049.html
Copyright © 2020-2023  润新知