题面
题意
给出一串数,每次询问给出l,r,求l,r之间的所有子串中,经过去重后,和的最大值是多少.
做法
这题和BZOJ4504 k个串相似,该题建出的主席树可以在线求以某个点为右端点时的区间最大值.
因为这题不要求在线,所以不要求线段树可持久化,因而可以根据询问的右端点进行排序,之后通过不断加入右端点,也就是区间[这个数上一次出现的位置 , 这个数的位置]加,直接用线段树求解.
比较两题,发现此题要求的是子串,因此右端点可以在r的右边,但是不难发现如果线段树上的每一个点都记录之前的最大值(右端点在r的左边时的最大值),那么得到的最大值就是答案.
下面具体讲一下如何维护每个点之前的最大值:
对于每个点除了左右儿子之外再维护下面四个值:
1.sum,在右端点为r时,也就是此时的最大值.
2.max_sum,目前所有r的最大值
3.bj,表示区间加的标记
4.max_bj,自上次下传标记以来的区间加标记前缀和的最大值
下传:
注意到此时的子节点的信息是上次下传之后的信息,因此它的max_sum可能是在这之间的某次操作得到的,也就是说:
node[son].max _sum=max(node[son].max _son,node[father].max _bj+node[son].sum.
其它标记则与普通线段树差不多.
void down(int u)
{
int p,q;
if(node[u].bjs||node[u].mx_b)
{
p=node[u].ls,q=node[u].rs;
node[p].mx_b=max(node[u].mx_b+node[p].bjs,node[p].mx_b);
node[q].mx_b=max(node[u].mx_b+node[q].bjs,node[q].mx_b);
node[p].bjs+=node[u].bjs;
node[q].bjs+=node[u].bjs;
node[p].mx_s=max(node[p].mx_s,node[p].sum+node[u].mx_b);
node[q].mx_s=max(node[q].mx_s,node[q].sum+node[u].mx_b);
node[p].sum+=node[u].bjs;
node[q].sum+=node[u].bjs;
node[u].bjs=node[u].mx_b=0;
}
}
代码
#include<iostream>
#include<cstdio>
#include<vector>
#include<map>
#define mid ((l+r)>>1)
#define N 100100
using namespace std;
int n,m,tt=1,num[N],ans[N];
map<int,int>last;
struct Node
{
int mx_s,bjs,sum,mx_b,ls,rs;
}node[N<<1];
struct Que
{
int a,id;
}tmp;
vector<Que>qu[N];
void build(int now,int l,int r)
{
if(l==r)
{
node[now].mx_s=0;
return;
}
if(l<=mid)
{
node[now].ls=++tt;
build(tt,l,mid);
}
if(mid<r)
{
node[now].rs=++tt;
build(tt,mid+1,r);
}
}
void down(int u)
{
int p,q;
if(node[u].bjs||node[u].mx_b)
{
p=node[u].ls,q=node[u].rs;
node[p].mx_b=max(node[u].mx_b+node[p].bjs,node[p].mx_b);
node[q].mx_b=max(node[u].mx_b+node[q].bjs,node[q].mx_b);
node[p].bjs+=node[u].bjs;
node[q].bjs+=node[u].bjs;
node[p].mx_s=max(node[p].mx_s,node[p].sum+node[u].mx_b);
node[q].mx_s=max(node[q].mx_s,node[q].sum+node[u].mx_b);
node[p].sum+=node[u].bjs;
node[q].sum+=node[u].bjs;
node[u].bjs=node[u].mx_b=0;
}
}
void add(int now,int l,int r,int u,int v,int w)
{
if(u==l&&v==r)
{
node[now].bjs+=w;
node[now].mx_b=max(node[now].bjs,node[now].mx_b);
node[now].sum+=w;
node[now].mx_s=max(node[now].mx_s,node[now].sum);
return;
}
down(now);
if(u<=mid) add(node[now].ls,l,mid,u,min(v,mid),w);
if(mid<v) add(node[now].rs,mid+1,r,max(u,mid+1),v,w);
node[now].sum=max(node[node[now].ls].sum,node[node[now].rs].sum);
node[now].mx_s=max(node[now].sum,node[now].mx_s);
}
int ask(int now,int l,int r,int u,int v)
{
if(l==u&&v==r)
{
return node[now].mx_s;
}
int res=-N;
down(now);
if(u<=mid) res=max(res,ask(node[now].ls,l,mid,u,min(mid,v)));
if(mid<v) res=max(res,ask(node[now].rs,mid+1,r,max(u,mid+1),v));
return res;
}
int main()
{
int i,j,p,q;
cin>>n;
for(i=1;i<=n;i++)
{
scanf("%d",&num[i]);
}
cin>>m;
for(i=1;i<=m;i++)
{
scanf("%d%d",&tmp.a,&p);
tmp.id=i;
qu[p].push_back(tmp);
}
build(1,1,n);
for(i=1;i<=n;i++)
{
add(1,1,n,last[num[i]]+1,i,num[i]);
last[num[i]]=i;
for(j=0;j<qu[i].size();j++)
{
ans[qu[i][j].id]+=ask(1,1,n,qu[i][j].a,i);
}
}
for(i=1;i<=m;i++)
{
printf("%d\n",ans[i]);
}
}