SPOJ GSS2 - Can you answer these queries II

题面

题意

给出一串数,每次询问给出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]);
    }
}

猜你喜欢

转载自blog.csdn.net/yzyyylx/article/details/80252014
今日推荐