zoukankan      html  css  js  c++  java
  • 【BZOJ3064】CPU监控(线段树)

    【BZOJ3064】CPU监控(线段树)

    题面

    BZOJ
    洛谷

    题解

    神仙(zsy)出在了(noip)模拟的题目。(然而(zsy)出的还是这题的升级版)
    首先明确一点,这题是一个吉司机线段树。
    如果只有区间加法,区间赋值,区间最大值,那么这题很简单。
    但是加上了一个区间历史最值,这就很烦了。
    于是我们就有了一个神仙做法,
    定义一个表示((a,b))表示区间内所有数先(+a)再和(b)(max),即(x=max(x+a,b))
    那么这样一来,区间加法转化成((a,-infty)),区间赋值变成了((-infty,b))
    考虑如何合并标记,现在有两个标记((a,b),(x,y)),将后者合并到前者上去。
    那么可以将标记转化成((a+x,max(b+x,y))),原因就是注意一下(max)和加法的先后顺序。
    对于两个标记如何合并(max),是((max(a,x),max(b,y)))。原因就是我们可以把这个标记看做是一个分段函数,那么这个合并就比较显然了。

    回到题目。
    这题到底在干什么呢?
    首先对于维护当前值,这个东西是非常显然的。
    考虑如何维护一个历史最值,我们对于每个点额外维护一个历史最值的标记,每次覆盖的时候不会覆盖掉历史最值的标记,只会用(max)操作更新历史最值标记。
    这样子似乎就可以做了。

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<vector>
    using namespace std;
    #define ll long long
    #define MAX 100100
    #define lson (now<<1)
    #define rson (now<<1|1)
    #define inf 1050000000
    inline int read()
    {
    	int x=0;bool t=false;char ch=getchar();
    	while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    	if(ch=='-')t=true,ch=getchar();
    	while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    	return t?-x:x;
    }
    struct Data
    {
    	int a,b;
    	void clear(){a=0;b=-inf;}
    	int calc(int x){return max(a+x,b);}
    }mxt[MAX<<2],tag[MAX<<2];
    int mx[MAX<<2],nw[MAX<<2];
    Data max(Data a,Data b){return (Data){max(a.a,b.a),max(a.b,b.b)};}
    Data operator+(Data a,Data b){return (Data){max(-inf,a.a+b.a),max(a.b+b.a,b.b)};}
    void pushup(int now)
    {
    	nw[now]=max(nw[lson],nw[rson]);
    	mx[now]=max(mx[lson],mx[rson]);
    }
    void puttag(int now,Data a,Data b)
    {
    	mxt[now]=max(mxt[now],tag[now]+b);
    	tag[now]=tag[now]+a;
    	mx[now]=max(mx[now],b.calc(nw[now]));
    	nw[now]=a.calc(nw[now]);
    }
    void pushdown(int now)
    {
    	puttag(lson,tag[now],mxt[now]);
    	puttag(rson,tag[now],mxt[now]);
    	mxt[now].clear();tag[now].clear();
    }
    void Build(int now,int l,int r)
    {
    	tag[now].clear();mxt[now].clear();
    	if(l==r){nw[now]=mx[now]=read();return;}
    	int mid=(l+r)>>1;
    	Build(lson,l,mid);Build(rson,mid+1,r);
    	pushup(now);
    }
    void Modify(int now,int l,int r,int L,int R,Data a)
    {
    	if(L<=l&&r<=R){puttag(now,a,a);return;}
    	int mid=(l+r)>>1;pushdown(now);
    	if(L<=mid)Modify(lson,l,mid,L,R,a);
    	if(R>mid)Modify(rson,mid+1,r,L,R,a);
    	pushup(now);
    }
    int Query(int now,int l,int r,int L,int R,int opt)
    {
    	if(L==l&&r==R)return opt?mx[now]:nw[now];
    	int mid=(l+r)>>1;pushdown(now);
    	if(R<=mid)return Query(lson,l,mid,L,R,opt);
    	if(L>mid)return Query(rson,mid+1,r,L,R,opt);
    	return max(Query(lson,l,mid,L,mid,opt),Query(rson,mid+1,r,mid+1,R,opt));
    }
    int n,m;
    char ch[20];
    int main()
    {
    	n=read();Build(1,1,n);m=read();
    	while(m--)
    	{
    		scanf("%s",ch);
    		int l=read(),r=read();Data a=(Data){-inf,-inf};
    		if(ch[0]=='Q')printf("%d
    ",Query(1,1,n,l,r,0));
    		else if(ch[0]=='A')printf("%d
    ",Query(1,1,n,l,r,1));
    		else if(ch[0]=='P')a.a=read(),Modify(1,1,n,l,r,a);
    		else a.b=read(),Modify(1,1,n,l,r,a);
    	}
    	return 0;
    }
    
    
  • 相关阅读:
    Linux C多线程实现生产者消费者
    数据库视图创建学习
    jsp生成好看的验证码
    每日英语
    ES6学习笔记(一)——let和const
    dataTables的导出Excel功能
    jquery生成二维码图片
    angular2表单初体验
    echarts系列之动态加载数据
    js刷新页面方法
  • 原文地址:https://www.cnblogs.com/cjyyb/p/9551064.html
Copyright © 2011-2022 走看看