[SP1557]GSS2 - Can you answer these queries II

题意不过只是比GSS1多了几个字而已,难度却把GSS1甩得望尘莫及。

给出n个数,q次询问,求最大子段和(可为空),相同的数只算一次

说到相同的只算一次这一条件,有点像[SDOI2009]HH的项链,但是本题不再是简简单单的统计个数,而是求最大子段和。

由于题目条件,GSS1的合并Lmax,Midmax,Rmax的方法以不再适用,我们必须另辟蹊径。

做题经验告诉我们,要处理有关区间去重的问题时,我们常用到离线算法,本题亦是如此。

仍然是用线段树,只不过我们要把序列中的元素一个个添加进去。

将所有询问按r排序,在最终处理询问到以r为区间右边界时,将a[r]添加到线段树。

线段树每个节点维护4个值,sum,hismax,sumtag,hismaxtag。

假设现在处理到以y为区间右边界的询问了,那么,对于叶结点

sum表示从这个叶结点所对应的原序列的下标x到y的所有元素和,及a[x]+a[x+1]+a[x+2]+...+a[y],

hismax表示sum的历史最大值(最小为0)。

对于内部节点

sum表示左右儿子的sum的最大值,

hismax表示左右儿子的hismax的最大值。

另外的,利用sumtag和hismaxtag作为延迟标记实现单次修改/询问O(logn)复杂度,具体意义参考代码。

如何向线段树添加元素?

记录序列中第i个元素上一个相同元素的位置pre[i],添加元素是[pre[i]+1,i]区间加a[i]即可。

如何查询?

查询[l,r]的hismax。

要特别注意pushdown()函数的更新顺序,非常容易弄错。

还有各种实现细节,一定要特别注意。

线段树不可多得的好题。

代码:

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstdlib>
 4 #include <cstring>
 5 #include <algorithm>
 6 using namespace std;
 7 typedef long long LL;
 8 inline LL read(){
 9     LL x=0,f=1;char ch=getchar();
10     while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
11     while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
12     return x*f;
13 }
14 const int MAXN=100005;
15 struct Node{
16     LL sum,hix,stag,htag;
17     Node(){
18         sum=hix=stag=htag=0;
19     }
20     friend Node operator + (Node lf,Node rt){
21         Node res;
22         res.sum=max(lf.sum,rt.sum);
23         res.hix=max(lf.hix,rt.hix);
24         return res;
25     }
26 }b[MAXN*4];
27 struct Qst{
28     int l,r,id;
29 }q[MAXN];
30 bool cmp(Qst x,Qst y){
31     return x.r<y.r;
32 }
33 int n,m,cur[MAXN*2],pre[MAXN],ql,qr;LL a[MAXN],ans[MAXN],k;
34 #define mid ((l+r)>>1)
35 #define lc (o<<1)
36 #define rc ((o<<1)|1)
37 void pushup(int o){
38     b[o]=b[lc]+b[rc];
39 }
40 void pushdown(int o){//注意更新先后顺序 
41     b[lc].hix=max(b[lc].hix,b[lc].sum+b[o].htag);
42     b[rc].hix=max(b[rc].hix,b[rc].sum+b[o].htag);
43     b[lc].sum+=b[o].stag;
44     b[rc].sum+=b[o].stag;
45     b[lc].htag=max(b[lc].htag,b[lc].stag+b[o].htag);
46     b[rc].htag=max(b[rc].htag,b[rc].stag+b[o].htag);
47     b[lc].stag+=b[o].stag;
48     b[rc].stag+=b[o].stag;
49     b[o].stag=b[o].htag=0;
50 }
51 void upd(int o,int l,int r){
52     if(ql<=l&&r<=qr){
53         b[o].sum+=k;
54         b[o].hix=max(b[o].hix,b[o].sum);
55         b[o].stag+=k;
56         b[o].htag=max(b[o].htag,b[o].stag);
57         return;
58     }
59     pushdown(o);
60     if(mid>=ql) upd(lc,l,mid);
61     if(mid<qr) upd(rc,mid+1,r);
62     pushup(o);
63 }
64 Node query(int o,int l,int r){
65     if(ql<=l&&r<=qr) return b[o];
66     pushdown(o);
67     if(mid<ql) return query(rc,mid+1,r);
68     else if(mid>=qr) return query(lc,l,mid);
69     else return query(lc,l,mid)+query(rc,mid+1,r);
70 }
71 int main(){
72     n=read();
73     for(int i=1;i<=n;i++){
74         a[i]=read();
75         pre[i]=cur[a[i]+(int)1e5];
76         cur[a[i]+(int)1e5]=i;
77     }
78     m=read();
79     for(int i=1;i<=m;i++){
80         q[i].l=read(),q[i].r=read();
81         q[i].id=i;
82     }
83     sort(q+1,q+m+1,cmp);
84     int j=1;
85     for(int i=1;i<=n;i++){
86         ql=pre[i]+1,qr=i,k=a[i];
87         upd(1,1,n);
88         for(;j<=m&&q[j].r<=i;j++){
89             ql=q[j].l,qr=q[j].r;
90             ans[q[j].id]=query(1,1,n).hix;
91         }
92     }
93     for(int i=1;i<=m;i++)
94         printf("%lld\n",ans[i]);
95     return 0;
96 }

猜你喜欢

转载自www.cnblogs.com/ErkkiErkko/p/9275653.html