解题:洛谷4314 CPU监控

题面

线段树·二重标记(什么鬼

用(a,b)标记表示先执行+a操作,然后对b取max,维护历史/当前最大值和历史/当前标记。然后我们发现区间加$x$就是$(x,-inf)$,区间赋$x$就是$(-inf,x)$。标记有两种更新,一种是和当前的标记合并,一种是更新历史标记。

把一个标记tag合并进当前标记ntag,显然新标记即

$(ntag.a+tag.a,max(ntag.b+tag.a,tag.b))$

把历史标记htag用一个标记tag更新更简单,其实就是对应取max

那么就可以做了:修改标记即先把当前标记和要加的标记合并,然后更新历史标记;修改最大值将当前最大值按标记意思改,然后历史最大值和当前最大值取max。下放标记类似

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 const int N=100005,inf=0x3f3f3f3f;
 6 struct a
 7 {
 8     int ad,mx;
 9     void init()
10     {
11         ad=0,mx=-inf;
12     }
13 }hist[4*N],nowt[4*N];
14 a operator + (a x,a y)
15 {
16     return (a){max(-inf,x.ad+y.ad),max(x.mx+y.ad,y.mx)};
17 }
18 a operator ^ (a x,a y)
19 {
20     return (a){max(x.ad,y.ad),max(x.mx,y.mx)};
21 }
22 int seq[N],hmax[4*N],nmax[4*N];
23 int n,m,t1,t2,t3; char str[10];
24 void Pushup(int nde)
25 {
26     int ls=2*nde,rs=2*nde+1;
27     hmax[nde]=max(hmax[ls],hmax[rs]);
28     nmax[nde]=max(nmax[ls],nmax[rs]);
29 }
30 void Apply(int nde,int tsk)
31 {
32     hist[nde]=hist[nde]^(nowt[nde]+hist[tsk]); nowt[nde]=nowt[nde]+nowt[tsk];
33     hmax[nde]=max(hmax[nde],max(nmax[nde]+hist[tsk].ad,hist[tsk].mx)); 
34     nmax[nde]=max(nmax[nde]+nowt[tsk].ad,nowt[tsk].mx); 
35 }
36 void Release(int nde)
37 {
38     int ls=2*nde,rs=2*nde+1;
39     Apply(ls,nde),Apply(rs,nde);
40     hist[nde].init(),nowt[nde].init();
41 }
42 void Create(int nde,int l,int r)
43 {
44     hist[nde].init(),nowt[nde].init();
45     if(l==r)
46         hmax[nde]=nmax[nde]=seq[l];
47     else
48     {
49         int mid=(l+r)/2,ls=2*nde,rs=2*nde+1;
50         Create(ls,l,mid),Create(rs,mid+1,r);
51         Pushup(nde);
52     }
53 }
54 void Change(int nde,int l,int r,int nl,int nr,a tsk)
55 {
56     if(l>nr||r<nl)
57         return ;
58     else if(l>=nl&&r<=nr)
59     {
60         hist[nde]=hist[nde]^(nowt[nde]+tsk); nowt[nde]=nowt[nde]+tsk;
61         hmax[nde]=max(hmax[nde],max(nmax[nde]+tsk.ad,tsk.mx)); 
62         nmax[nde]=max(nmax[nde]+tsk.ad,tsk.mx);
63     }
64     else
65     {
66         int mid=(l+r)/2,ls=2*nde,rs=2*nde+1; Release(nde);
67         Change(ls,l,mid,nl,nr,tsk),Change(rs,mid+1,r,nl,nr,tsk);
68         Pushup(nde);
69     }
70 }
71 int Query(int nde,int l,int r,int nl,int nr,int typ)
72 {
73     if(l>nr||r<nl)
74         return -inf;
75     else if(l>=nl&&r<=nr)
76         return typ?nmax[nde]:hmax[nde];
77     else
78     {
79         int mid=(l+r)/2,ls=2*nde,rs=2*nde+1; Release(nde);
80         return max(Query(ls,l,mid,nl,nr,typ),Query(rs,mid+1,r,nl,nr,typ));
81     }
82 }
83 int main()
84 {
85     scanf("%d",&n);
86     for(int i=1;i<=n;i++)
87         scanf("%d",&seq[i]);
88     Create(1,1,n),scanf("%d",&m);
89     for(int i=1;i<=m;i++)
90     {
91         scanf("%s%d%d",str,&t1,&t2);
92         if(str[0]=='Q') printf("%d\n",Query(1,1,n,t1,t2,1));
93         else if(str[0]=='A') printf("%d\n",Query(1,1,n,t1,t2,0));
94         else if(str[0]=='P') scanf("%d",&t3),Change(1,1,n,t1,t2,(a){t3,-inf});
95         else if(str[0]=='C') scanf("%d",&t3),Change(1,1,n,t1,t2,(a){-inf,t3});
96     }
97     return 0;
98 }
View Code

 

转载于:https://www.cnblogs.com/ydnhaha/p/10181265.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值