题意不过只是比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 }