zoukankan      html  css  js  c++  java
  • 联赛模拟测试20 C. Weed 线段树

    题目描述

    (duyege) 的电脑上面已经长草了,经过辨认上面有金坷垃的痕迹。
    为了查出真相,(duyege) 准备修好电脑之后再进行一次金坷垃的模拟实验。
    电脑上面有若干层金坷垃,每次只能在上面撒上一层高度为 (v_i)的金坷垃
    或者除掉最新(v_i) 层(不是量)撒的金坷垃。如果上面只留有不足(v_i) 层金坷垃,那么就相当于电脑上面没有金坷垃了。
    (duyege) 非常严谨,一开始先给你 (m) 个上述操作要你依次完成。
    然后又对实验步骤进行了(q)次更改,每次更改都会改变其中一个操作为另外一个操作。
    每次修改之后都会询问最终金坷垃的量有多少。

    输入格式

    输入第一行为两个正整数(m)(q) ,接下来 (m) 行每行(2) 个整数 (k)(v_i)(k)(0)时撒金坷垃,为(1) 时除金坷垃。
    接下来(q) 行每行(3) 个整数 (c_i)(k)(v_i) , 代表被更改的操作是第 (c_i) 个,
    后面(2)个数描述更改为这样的操作。

    输出格式

    输出(q)行代表每次金坷垃的量为多少

    样例

    样例输入

    10 5
    0 10
    1 5
    0 13
    0 18
    0 2
    1 1
    0 8
    0 9
    1 3
    0 7
    9 0 3
    10 1 7
    6 0 8
    10 0 5
    8 1 2

    样例输出

    58
    0
    0
    66
    41

    数据范围与提示

    对于 (30\%)的数据,(m leq 1000,q leq 1000)
    .
    对于另外 (20\%) 的数据,每次(k=1) 时都会将金坷垃清空。
    对于 100%的数据,(m leq 2 imes 10^5,q leq 2 imes 10^5,v_i leq 10^4) .

    分析

    考场上 (20) 分暴力打挂,只因一个 (continue)

    for(rg int i=1;i<=q;i++){
    	aa=read(),bb=read(),cc=read();
    	if(b[aa].op==0){
    		if(bb==0){
    			ad(aa,-b[aa].val);
    			ad(aa,cc);
    		} else {
    			now=cx(aa)-cx(aa-1);
    			ad(aa,-now);
    			xg(1,aa,aa);	
    		}
    	} else {
    		if(bb) continue;
    		else {
    			xg(1,aa,0);
    			ad(aa,cc);
    		}
    	}
    	b[aa].op=bb,b[aa].val=cc;
    	now=shu[1].mmin;
    	if(now==0) printf("%d
    ",cx(m));
    	else printf("%d
    ",cx(m)-cx(now));
    }
    
    for(rg int i=1;i<=q;i++){
    	aa=read(),bb=read(),cc=read();
    	if(b[aa].op==0){
    		if(bb==0){
    			ad(aa,-b[aa].val);
    			ad(aa,cc);
    		} else {
    			now=cx(aa)-cx(aa-1);
    			ad(aa,-now);
    			xg(1,aa,aa);	
    		}
    	} else {
    		if(!bb) {
    			xg(1,aa,0);
    			ad(aa,cc);
    		}
    	}
    	b[aa].op=bb,b[aa].val=cc;
    	now=shu[1].mmin;
    	if(now==0) printf("%d
    ",cx(m));
    	else printf("%d
    ",cx(m)-cx(now));
    }
    

    正解用线段树维护
    每个点记录三个值:执行完这段操作后会删多少个,再插多少个,插的和一共是多少
    合并值时再用一个函数查找左孩子被从右删除若干个后剩下的插入总和是多少
    注意查找时,如果右儿子的层数大于清除的层数
    应该写成

    return tr[da].sum-tr[da<<1|1].sum+cx(da<<1|1,cnt);
    

    而不是

    return tr[da<<1].sum+cx(da<<1|1,cnt);
    

    比如这样的数据('-'代表删除)

    ++++ -+++

    代码

    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<cstring>
    #define rg register
    inline int read(){
    	rg int x=0,fh=1;
    	rg char ch=getchar();
    	while(ch<'0' || ch>'9'){
    		if(ch=='-') fh=-1;
    		ch=getchar();
    	}
    	while(ch>='0' && ch<='9'){
    		x=(x<<1)+(x<<3)+(ch^48);
    		ch=getchar();
    	}
    	return x*fh;
    }
    const int maxn=1e6+5;
    int m,q;
    struct asd{
    	int op,val;
    	asd(){}
    	asd(int aa,int bb){
    		op=aa,val=bb;
    	}
    }b[maxn];
    struct trr{
    	int l,r,sum,cnt,del;
    }tr[maxn];
    int cx(int da,int cnt){
    	if(tr[da<<1|1].cnt==cnt){
    		return tr[da].sum-tr[da<<1|1].sum;
    	} else if(tr[da<<1|1].cnt>cnt){
    		return tr[da].sum-tr[da<<1|1].sum+cx(da<<1|1,cnt);
    	} else {
    		return cx(da<<1,cnt-tr[da<<1|1].cnt+tr[da<<1|1].del);
    	}
    }
    void push_up(int da){
    	if(tr[da<<1|1].del>tr[da<<1].cnt){
    		tr[da].del=tr[da<<1].del+tr[da<<1|1].del-tr[da<<1].cnt;
    		tr[da].cnt=tr[da<<1|1].cnt;
    		tr[da].sum=tr[da<<1|1].sum;
    	} else if(tr[da<<1|1].del==0){
    		tr[da].del=tr[da<<1].del;
    		tr[da].sum=tr[da<<1].sum+tr[da<<1|1].sum;
    		tr[da].cnt=tr[da<<1].cnt+tr[da<<1|1].cnt;
    	} else {
    		tr[da].del=tr[da<<1].del;
    		tr[da].cnt=tr[da<<1].cnt+tr[da<<1|1].cnt-tr[da<<1|1].del;
    		if(tr[da<<1].cnt==tr[da<<1|1].del) tr[da].sum=tr[da<<1|1].sum;
    		else tr[da].sum=tr[da<<1|1].sum+cx(da<<1,tr[da<<1|1].del);
    	}
    }
    void build(int da,int l,int r){
    	tr[da].l=l,tr[da].r=r;
    	if(tr[da].l==tr[da].r){
    		if(b[l].op==1){
    			tr[da].del=b[l].val;
    		} else {
    			tr[da].cnt=1;
    			tr[da].sum=b[l].val;
    		}
    		return;
    	}
    	rg int mids=(tr[da].l+tr[da].r)>>1;
    	build(da<<1,l,mids);
    	build(da<<1|1,mids+1,r);
    	push_up(da);
    }
    void xg(int da,int wz){
    	if(tr[da].l==tr[da].r){
    		if(b[wz].op==1){
    			tr[da].del=b[wz].val;
    			tr[da].cnt=tr[da].sum=0;
    		} else {
    			tr[da].del=0;
    			tr[da].cnt=1;
    			tr[da].sum=b[wz].val;
    		}
    		return;
    	}
    	rg int mids=(tr[da].l+tr[da].r)>>1;
    	if(wz<=mids) xg(da<<1,wz);
    	else xg(da<<1|1,wz);
    	push_up(da);
    }
    int main(){
    	freopen("weed.in","r",stdin);
    	freopen("weed.out","w",stdout);
    	m=read(),q=read();
    	for(rg int i=1;i<=m;i++){
    		b[i].op=read(),b[i].val=read();
    	}
    	build(1,1,m);
    	rg int aa,bb,cc;
    	for(rg int i=1;i<=q;i++){
    		aa=read(),bb=read(),cc=read();
    		b[aa].op=bb,b[aa].val=cc;
    		xg(1,aa);
    		printf("%d
    ",tr[1].sum);
    	}
    	return 0;
    }
    
  • 相关阅读:
    QT编译时 cc1plus进程占用大量内存卡死问题解决
    python import cv2 出错:cv2.x86_64-linux-gnu.so: undefined symbol
    python ImportError: No module named builtins
    OSError: libcudart.so.7.5: cannot open shared object file: No such file or directory
    二维数组和二级指针(转)
    C/C++中无条件花括号的妙用
    C语言中do...while(0)的妙用(转载)
    卸载 ibus 使Ubuntu16.04任务栏与启动器消失 问题解决
    关于Qt creator 无法使用fcitx输入中文的问题折腾
    QT error: cannot find -lGL
  • 原文地址:https://www.cnblogs.com/liuchanglc/p/13856930.html
Copyright © 2011-2022 走看看