P4314 CPU监控

P4314 CPU监控

好一道神仙题

思路来源于yyb神仙

题目要求我们支持4个操作:

区间赋值

区间加

区间最大值

区间历史最大值

这第四个操作简直是BUG一样的存在

思考一下,发现难点在于维护区间历史最大值

先打完这些:

#include<bits/stdc++.h>
using namespace std;
const int N=100005;
#define INF 1050000000
struct TAG{
    #define il inline
    int a,b;
    il void clear(){a=0,b=-INF;}
    il int number(int x){return max(a+x,b);}
};
int n,m;
int a[N];
struct Sugment_Tree{//0:目前最大值 1:历史最大值
    #define mid (l+r)/2
    #define il inline
    Sugment_Tree(){

    }
    il void push_up(int num){

    }
    il void put_tag(int num,TAG a,TAG b){

    }
    il void push_down(int num){

    }
    il void build(int l,int r,int num){
        if(l==r){

        }
        build(l,mid,num<<1);
        build(mid+1,r,num<<1|1);
        push_up(num);
    }
    il void change(int l,int r,int num,int L,int R,TAG X){
        if(l>R||r<L) return;
        if(l>=L&&r<=R){

            return;
        }
        push_down(num);
        change(l,mid,num<<1,L,R,X);
        change(mid+1,r,num<<1|1,L,R,X);
    }
    il int ask(int l,int r,int num,int L,int R,int opt){
        if(l>R||r<L) return 0;
        if(l>=L&&r<=R){

        }
        push_down(num);
        return max(ask(l,mid,num<<1,L,R,opt),ask(mid+1,r,num<<1|1,L,R,opt));
    }
}T;
char s[5];
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    T.build(1,n,1);
    scanf("%d",&m);
    while(m--){
        int l,r,X;
        scanf("%s",s);
        if(s[0]==‘Q‘){
            scanf("%d%d",&l,&r);
            int p=T.ask(1,n,1,l,r,0);
            printf("%d\n",p);
        }
        else if(s[0]==‘A‘){
            scanf("%d%d",&l,&r);
            int p=T.ask(1,n,1,l,r,1);
            printf("%d\n",p);
        }
        else if(s[0]==‘P‘){
            scanf("%d%d%d",&l,&r,&X);
            TAG p;
            p.clear();
            p.a=X;
            T.change(1,n,1,l,r,p);
        }
        else{
            scanf("%d%d%d",&l,&r,&X);
            TAG p;
            p.clear();
            p.b=X;
            T.change(1,n,1,l,r,p);
        }
    }
    return 0;
} 

记住,inf不能太大,否则待会会爆int

然后开始一步一步想。

先给出神仙思路:

定义一个表示(a,b)表示区间内所有数先+a再和b取max,即x=max(x+a,b)
那么这样一来,区间加法转化成(a,−∞),区间赋值变成了(−∞,b)

这个思路的好处是将两种操作当成了一种来做

理论上,我们对每一个区间只要维护区间目前最大值、区间历史最大值、区间标记即可

但是历史最值还是维护不了。

考虑如何维护一个历史最值,我们对于每个点额外维护一个历史最值的标记,每次覆盖的时候不会覆盖掉历史最值的标记,只会用max操作更新历史最值标记。

接下来分段看

il void push_up(int num){
    t[num]=max(t[num<<1],t[num<<1|1]);
    hm[num]=max(hm[num<<1],hm[num<<1|1]);
}

这个push_up比较常规,不说

il void push_down(int num){
        put_tag(num<<1,tag[num],mtg[num]);
        put_tag(num<<1|1,tag[num],mtg[num]);
        mtg[num].clear();
        tag[num].clear();
    }

不妨让我们来思考一下:

这是一个下传图示

假设现在num<<1,num<<1|1上没有标记,num要下传

我们分别调用push_tag函数,合并标记

il void put_tag(int num,TAG a,TAG b){
        mtg[num]=max(mtg[num],tag[num]+b);
        tag[num]=tag[num]+a;
        hm[num]=max(hm[num],b.number(t[num]));
        t[num]=a.number(t[num]);
    }

精髓部分

第一行:mtg代表历史标记最值

这一行里我们所做的是维护历史最值标记

tag是当前标记

b是父亲节点的mtg

要是想要更新num的mtg,那么父亲节点必须选取mtg才最有可能

然后就有了第一行

+和max等下再说

第二行:tag代表目前标记

我们只需要把现在父亲传给num的标记合并上即可

第三行:hm表示历史最值

t表示当前最值

我们考虑,b是父亲的历史最值标记

这个标记有可能之前被修改了

b.number(x)代表x经过b操作之后的值与x比的较大值

说白了,就是试试看现在的num历史最值和当前num最值+b操作之后会不会改变历史

第四行:直接看看t会不会改变

TAG max(TAG x,TAG y){
    return (TAG){max(x.a,y.a),max(x.b,y.b)};
}
TAG operator+ (TAG x,TAG y){
    return (TAG){max(-INF,x.a+y.a),max(x.b+y.a,y.b)};
}

这两行就是标记的max与+

可以发现,max实际上就是最大的+拼上最大的max

比如:

操作 A(1,3) B(-2,6)

当前数组为1 4 2

什么都不做:最大值4 历史最大值4

做了A之后:最大值5 历史最大值5

做了B之后:最大值6 历史最大值6

对于两个标记如何合并max,是(max(a,x),max(b,y))。原因就是我们可以把这个标记看做是一个分段函数,那么这个合并就比较显然了。

那么取max后就是C(1,6)

(原因:max很好理解,而+是迟早要加的)

合并:

考虑先后顺序,加法并一起,max的话,分两种:先变max再加x或者直接变max(sum,y)

原因就是注意一下maxmax和加法的先后顺序。

il void change(int l,int r,int num,int L,int R,TAG X){
        if(l>R||r<L) return;
        if(l>=L&&r<=R){
            put_tag(num,X,X);
            return;
        }
        push_down(num);
        change(l,mid,num<<1,L,R,X);
        change(mid+1,r,num<<1|1,L,R,X);
        push_up(num);
    }

线段树部分只有这个操作可说了。

为什么我们直接put_tag?

因为num的父亲也做了,然后拖到这一步做而已。

代码(完整)

#include<bits/stdc++.h>
using namespace std;
const int N=100005;
#define INF 1050000000
struct TAG{
    #define il inline
    int a,b;
    il void clear(){a=0,b=-INF;}
    il int number(int x){return max(a+x,b);}
};
int n,m;
int a[N];

TAG max(TAG x,TAG y){
    return (TAG){max(x.a,y.a),max(x.b,y.b)};
}
TAG operator+ (TAG x,TAG y){
    return (TAG){max(-INF,x.a+y.a),max(x.b+y.a,y.b)};
}
struct Sugment_Tree{//0:目前最大值 1:历史最大值
    #define mid (l+r)/2
    #define il inline
    TAG mtg[N<<2];//历史最值标记,每次覆盖的时候不会覆盖掉历史最值的标记,只会用max操作更新历史最值标记。
    TAG tag[N<<2];//普通标记
    int t[N<<2];//目前最值
    int hm[N<<2];//历史最值
    il void push_up(int num){
        t[num]=max(t[num<<1],t[num<<1|1]);
        hm[num]=max(hm[num<<1],hm[num<<1|1]);
    }
    il void put_tag(int num,TAG a,TAG b){
        mtg[num]=max(mtg[num],tag[num]+b);
        tag[num]=tag[num]+a;
        hm[num]=max(hm[num],b.number(t[num]));
        t[num]=a.number(t[num]);
    }
    il void push_down(int num){
        put_tag(num<<1,tag[num],mtg[num]);
        put_tag(num<<1|1,tag[num],mtg[num]);
        mtg[num].clear();
        tag[num].clear();
    }
    il void build(int l,int r,int num){
        mtg[num].clear();
        tag[num].clear();
        if(l==r){
            t[num]=hm[num]=a[l];
            return;
        }
        build(l,mid,num<<1);
        build(mid+1,r,num<<1|1);
        push_up(num);
    }
    il void change(int l,int r,int num,int L,int R,TAG X){
        if(l>R||r<L) return;
        if(l>=L&&r<=R){
            put_tag(num,X,X);
            return;
        }
        push_down(num);
        change(l,mid,num<<1,L,R,X);
        change(mid+1,r,num<<1|1,L,R,X);
        push_up(num);
    }
    il int ask(int l,int r,int num,int L,int R,int opt){
        if(l>R||r<L) return -INF;
        if(l>=L&&r<=R){

            return opt?hm[num]:t[num];
        }
        push_down(num);
        return max(ask(l,mid,num<<1,L,R,opt),ask(mid+1,r,num<<1|1,L,R,opt));
    }
}T;
char s[5];
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    T.build(1,n,1);
    scanf("%d",&m);
    while(m--){
    //    printf("%d &&&&&&&&&&&&&&&&&\n",T.hm[15]);
        int l,r,X;
        scanf("%s",s);
        TAG p=(TAG){-INF,-INF};
        if(s[0]==‘Q‘){
            scanf("%d%d",&l,&r);
            int p=T.ask(1,n,1,l,r,0);
            printf("%d\n",p);
        }
        else if(s[0]==‘A‘){
            scanf("%d%d",&l,&r);
            int p=T.ask(1,n,1,l,r,1);
            printf("%d\n",p);
        }
        else if(s[0]==‘P‘){
            scanf("%d%d%d",&l,&r,&X);

            p.a=X;
            T.change(1,n,1,l,r,p);
        }
        else{
            scanf("%d%d%d",&l,&r,&X);

            p.b=X;
            T.change(1,n,1,l,r,p);
        }
    }
    return 0;
} 

原文地址:https://www.cnblogs.com/QYJ060604/p/11748284.html

时间: 2024-10-03 00:12:09

P4314 CPU监控的相关文章

C#实现对远程服务器的内存和CPU监控

C#实现对远程服务器的内存和CPU监控小记 1.  主要使用到的组件有System.Management.dll 2.  主要类为 :ManagementScope 连接远程服务器示例代码: 1 private const string PROPERTY_CAPACITY = "Capacity"; 2 private const string PROPERTY_AVAILABLE_BYTES = "AvailableBytes"; 3 private const

CPU监控 解题报告

CPU监控 这种题就需要小黄鸭调试法,不行就重构,动态gdb可能会死人,一堆tag的... 维护历史最值的一个核心是历史最值tag,它的意义是从上一次这个点下放tag之后到当前时刻的这个点的tag达到过的最大值. 我们注意到tag的作用是按找时间限制的,所以我们可以认为历史最大tag是一个前缀最大值. 有了历史最值tag,我们就可以完成pushdown的工作辣 就把历史tag放给儿子的历史tag和历史最值,这时候更新需要用儿子的当前值结合自己的历史最大进行更新. 对这个题维护一个二元组\(tag

安卓app测试之cpu监控

安卓app测试之cpu监控,如何获取监控的cpu数据呢? 一.通过Dumpsys 来取值 1.adb shell dumpsys cpuinfo 二.top 1.top -d 1|grep packageName adb shell "top -d 1|grep tv.danmaku.bili" 原文地址:https://www.cnblogs.com/wuzm/p/10969003.html

cpu监控数据及cpu几核关系

1.监控CPU,主要有%processor time 和CPU队列长度(Processor __), 一般%processor time≤75%正常 Cpu队列长度 值如果一直大于 核数,说明进程一直排队,存在处理器瓶颈,引起处理器堵塞,可能会影响事务成功率等 2.查看几核方法 方法一:点击资源管理器(ctrl+alt+delete),点击性能监视器,查看CPU,个数 方法二:点击我的电脑---属性---设备管理器---处理器,查看处理器个数

cpu监控

在对服务器进行维护时,有时也遇到由于系统 CPU(利用率)负载 过量导致业务中断的情况.服务器上可能运行多个进程,查看单个进程的 CPU 都是正常的,但是整个系统的 CPU 负载可能是异常的.通过脚本对系统 CPU 负载进行时时监控,可以在异常时及时发送告警,便于维护人员及时处理,预防事故发生.下面的函数可以检测系统 CPU 使用情况 . 使用 vmstat 取 5 次系统 CPU 的 idle 值,取平均值,然后通过与 100 取差得到当前 CPU 的实际占用值. function GetSy

基于Flink秒级计算时CPU监控图表数据中断问题

基于Flink进行秒级计算时,发现监控图表中CPU有数据中断现象,通过一段时间的跟踪定位,该问题目前已得到有效解决,以下是解决思路: 一.问题现象 以SQL02为例,发现本来10秒一个点的数据,有时会出现断点现象,会少1-2个点甚至更多: 二.问题定位 针对该问题,根据数据处理链路,制定了数据输出跟踪示意图,如下所示: 通过输出的实际数据发现: 1.监控Agent的数据已经正确上报Kafka 2.从Kafka中可以正确取到监控Agent上报的数据 3.从计算完毕的Kafka中取不到丢失点的数据

inux CPU监控分析

一.vmstat 可对操作系统的虚拟内存.进程.CPU活动进行监控 Procs(进程) r: 运行队列中进程数量,这个值也可以判断是否需要增加CPU.(长期大于1) b: 等待IO的进程数量. Memory(内存) swpd: 使用虚拟内存大小,如果swpd的值不为0,但是SI,SO的值长期为0,这种情况不会影响系统性能. free: 空闲物理内存大小. buff: 用作缓冲的内存大小. cache: 用作缓存的内存大小,如果cache的值大的时候,说明cache处的文件数多,如果频繁访问到的文

【我的Linux,我做主!】CPU监控命令之pidstat、mpstat命令

目录:(一)pidstat简介(二)mpstat简介 (一)pidstat简介(1.1)pidstat主要用于监控全部或指定进程占用系统资源的情况,如CPU.内存.设备IO.任务切换.线程等,pidstat首次运行时显示自系统启动开始的各项统计信息,之后运行pidstat将显示自上次运行该命令以后的统计信息.用户可以通过指定统计的次数和时间来获得所需的统计信息.(1.2)常用的命令格式# pidstat [参数] [时间] [次数](1.3)命令参数常见的命令参数如下:-u:默认的参数,显示各个

cpu监控:mpstat命令

mpstat是MultiProcessor Statistics的缩写,是实时系统监控工具.报告CPU的一些统计信息,这些信息存放在/proc/stat文件中.在多CPUs系统里,其不但能查看所有CPU的平均状况信息,而且能够查看特定CPU的信息. 语法: mpstat [-P {|ALL}] [internal [count]] 参数:     (1)-P {|ALL}:表示监控哪个CPU,在[0,cpu个数-1]中取值:     (2)internal:相邻的两次采样的间隔时间:     (