求最大子段和,但是相同的数只算一次。
在现很难完成,可以考虑离线。
离线方法很trick
把原数组按读入顺序加入,用s[i]维护s[i]到当前加入的和(不重复计算)
如何维护这个和?很简单,只要用线段树把pre[i]+1~i的s都加上a[i]即可
把询问按照右端点排序,对于询问[l,r],我们只要在加入r之后查找s[l~r]曾今的最大值即可
这个怎么用线段树维护?可持久化?似乎会爆空间。。。
其实不需要可持久化那种高端的东西,我们只需要一个线段树,打上几个标记就行了
curmax 当前区间内最大的s
curtip 当前整个区间的变化标记
pstmax 历史上区间内最大的s
psttip 历史上整个区间的变化标记的最大值
传递的时候仔细考虑以下就可以了
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int Maxn = 400005; int curmax[Maxn], curtip[Maxn]; int pstmax[Maxn], psttip[Maxn]; int ans[Maxn],pre[Maxn],pos[Maxn]; int a[Maxn],b[Maxn]; int n,m,i,j,Q; struct arr { int l,r,num; bool operator <(const arr &a)const { return r<a.r; } } q[Maxn]; void push(int p){ if (curmax[p*2+1]+psttip[p]>pstmax[p*2+1]) pstmax[p*2+1] = curmax[p*2+1]+psttip[p]; if (curmax[p*2+2]+psttip[p]>pstmax[p*2+2]) pstmax[p*2+2] = curmax[p*2+2]+psttip[p]; curmax[p*2+1] += curtip[p]; curmax[p*2+2] += curtip[p]; if (curtip[p*2+1]+psttip[p]>psttip[p*2+1]) psttip[p*2+1] = curtip[p*2+1]+psttip[p]; if (curtip[p*2+2]+psttip[p]>psttip[p*2+2]) psttip[p*2+2] = curtip[p*2+2]+psttip[p]; curtip[p*2+1] += curtip[p]; curtip[p*2+2] += curtip[p]; curtip[p] = psttip[p] = 0; } void add(int p,int l,int r,int L,int R,int dlt){ if (L>r || l>R) return; if (L<=l && R>=r){ curtip[p] += dlt; curmax[p] += dlt; if (curtip[p]>psttip[p]) psttip[p] = curtip[p]; if (curmax[p]>pstmax[p]) pstmax[p] = curmax[p]; return; } if (curtip[p]) push(p); int mid = (l+r)>>1; add(p*2+1,l,mid,L,R,dlt); add(p*2+2,mid+1,r,L,R,dlt); curmax[p] = max(curmax[p*2+1], curmax[p*2+2]); pstmax[p] = max(pstmax[p*2+1], pstmax[p*2+2]); } int query(int p,int l,int r,int L,int R){ if (L>r || l>R) return 0; if (L<=l && R>=r) return pstmax[p]; if (curtip[p]) push(p); int mid = (l+r)>>1; return max(query(p*2+1,l,mid,L,R), query(p*2+2,mid+1,r,L,R) ); } int main(){ freopen("gss2.in","r",stdin); freopen("gss2.out","w",stdout); scanf("%d",&n); for (i=1;i<=n;i++){ scanf("%d",&a[i]); b[i] = a[i]; } sort(b+1,b+n+1); m = unique(b+1,b+n+1)-b-1; for (i=1;i<=n;i++){ int t = lower_bound(b+1,b+m+1,a[i])-b; pre[i] = pos[t]; pos[t] = i; } scanf("%d",&Q); for (i=1;i<=Q;i++){ scanf("%d%d",&q[i].l,&q[i].r); q[i].num = i; } sort(q+1,q+Q+1); for (i=1,j=1;i<=n;i++){ add(0,1,n,pre[i]+1,i,a[i]); while (j<=Q&&q[j].r==i){ ans[q[j].num] = query(0,1,n,q[j].l,i); j++; } } for (i=1;i<=Q;i++) printf("%d\n",ans[i]); return 0; }