最大连续子序和 (加强版?)

来源:互联网 发布:吴亦凡 扒皮 知乎 编辑:程序博客网 时间:2024/06/06 20:25

题目描述 Description

给你K个序列(编号从0到K-1),并且第i个序列有Ni个元素。然后将会有一个由(0~K-1)组成的字符串S=(s1,s2,...,sn)。如果si=p,

那么把第p个序列增加到这个大的序列上。

例如:

如果你有小的序列:

0.{1,2,3}

1.{-1,2,0}

2.{3,4,5,-6}

字符串S="1021",那么这个大的序列是{-1,2,0,1,2,3,3,4,5,-6,-1,2,0}

接下来,对于大的序列将会有M组询问如下:

Query(x, y) = Max{a[i] + a[i + 1] + ... + a[j] ; 1 <= x <= i <= j <= y <= len(大序列的长度)}.

输入描述 Input Description

第一行有两个整数K, M。

接下来K行,每行开始用一个整数Ni,表示小的序列的个数,接下来Ni个整数每个整数的绝对值范围不超过100,000 。

然后是有一个由(0~K-1)组成的字符串S。

接下来M行,每行两个整数x, y代表每组询问。(1 <= x <= y <= len(大序列的长度))。

输出描述 Output Description

对于每组询问输出答案。

样例输入 Sample Input

3 3

3 1 -2 3

3 5 6 -7

4 2 0 6 8

0120

1 3

4 6

4 13

样例输出 Sample Output

3 11 22

20%的数据中1<=K<=3,1<=M<=10,1<=Ni<=10,1<=S<=10;

40%的数据中1<=K<=10,1<=M<=1000,1<=Ni<=100,1<=S<=100;

60%的数据中1<=K<=10,1<=M<=10000,1<=Ni<=1000,1<=S<=1000;

100%的数据中1<=K<=10,1<=M<=100000,1<=Ni<=10000,1<=S<=100000;

传送门:http://codevs.cn/problem/2012/
题目大意:中文题,自己看咯。
题目分析:其实就是求给定区间内的最大子段和。只要写个裸的线段树,记录几个值就是啦。考虑到父区间的最大子段可能是左子区间内的最大段也可能是右区间内的又或者是跨过中间左右都有。那么我们只需要记录子区间的lmax,mmax,rmax。mmax是该区间的最大子段和,lmax是从左端点起得最大子段和,rmax同 lmax啦。然后合并到父区间就很简单啦。题目本来是很简单的,可是突然凑出个S串。其实只要再建一棵总树。总共k+1棵线段树就是辣。在询问的时候多个判断就是了。
PS:好久没写线段树,那么快写出一个,又那么久没写题解了,就拿来凑一个了。代码风格有点丑,空间也不省,如果谁有更好的姿势,请一定要教我~
#include<cmath>#include<cstdio>#include<vector>#include<cstring>#include<iostream>#include<algorithm>using namespace std;struct node {    int l,r;///左闭右开    long long ll,rr,lmax,mmax,rmax,sum;};char s[100010];int n[12],aa[100010],a[12][10100];long long ssum[100010];node f[12][100000],tree[1000000];void build_tree(int i,int g,int l,int r){    f[i][g].l=l;f[i][g].r=r;    if (l+1>=r) {        f[i][g].lmax=a[i][l];f[i][g].mmax=a[i][l];        f[i][g].rmax=a[i][l];f[i][g].sum=a[i][l];        return ;    }    build_tree(i,2*g,l,(l+r)/2);    build_tree(i,2*g+1,(l+r)/2,r);    f[i][g].lmax=max(f[i][2*g].lmax,f[i][2*g].sum+f[i][2*g+1].lmax);    f[i][g].rmax=max(f[i][2*g+1].rmax,f[i][2*g+1].sum+f[i][2*g].rmax);    f[i][g].sum=f[i][2*g].sum+f[i][2*g+1].sum;    f[i][g].mmax=max(f[i][2*g].mmax,f[i][2*g+1].mmax);    f[i][g].mmax=max(f[i][g].mmax,f[i][g].lmax);    f[i][g].mmax=max(f[i][g].mmax,f[i][g].rmax);    f[i][g].mmax=max(f[i][g].mmax,f[i][2*g].rmax+f[i][2*g+1].lmax);}void build_trees(int g,int l,int r){    tree[g].l=l;tree[g].r=r;    if (l+1>=r) {        tree[g].ll=ssum[l-1]+1;tree[g].rr=ssum[l];        tree[g].lmax=f[aa[l]][1].lmax;tree[g].rmax=f[aa[l]][1].rmax;        tree[g].mmax=f[aa[l]][1].mmax;tree[g].sum=f[aa[l]][1].sum;        return ;    }    build_trees(2*g,l,(l+r)/2);    build_trees(2*g+1,(l+r)/2,r);    tree[g].ll=tree[2*g].ll;tree[g].rr=tree[2*g+1].rr;    tree[g].lmax=max(tree[2*g].lmax,tree[2*g].sum+tree[2*g+1].lmax);    tree[g].rmax=max(tree[2*g+1].rmax,tree[2*g+1].sum+tree[2*g].rmax);    tree[g].sum=tree[2*g].sum+tree[2*g+1].sum;    tree[g].mmax=max(tree[2*g].mmax,tree[2*g+1].mmax);    tree[g].mmax=max(tree[g].mmax,tree[g].lmax);    tree[g].mmax=max(tree[g].mmax,tree[g].rmax);    tree[g].mmax=max(tree[g].mmax,tree[2*g].rmax+tree[2*g+1].lmax);}node getmax(int i,int g,long long l,long long r){    node ret,lret,rret;    if (f[i][g].l==l&&f[i][g].r-1==r) return f[i][g];    if (r<f[i][2*g].r) return getmax(i,2*g,l,r);    else if (l>=f[i][2*g+1].l) return getmax(i,2*g+1,l,r);        else {            lret=getmax(i,2*g,l,f[i][2*g].r-1);            rret=getmax(i,2*g+1,f[i][2*g+1].l,r);            ret.lmax=max(lret.lmax,lret.sum+rret.lmax);            ret.rmax=max(rret.rmax,rret.sum+lret.rmax);            ret.mmax=max(lret.mmax,rret.mmax);            ret.mmax=max(ret.mmax,ret.lmax);            ret.mmax=max(ret.mmax,ret.rmax);            ret.mmax=max(ret.mmax,lret.rmax+rret.lmax);            return ret;        }}node getmaxs(int g,long long l,long long r){    node ret,lret,rret;    if (tree[g].ll==l&&tree[g].rr==r) return tree[g];    if (tree[g].l+1>=tree[g].r) return getmax(aa[tree[g].l],1,l-ssum[tree[g].l-1],r-ssum[tree[g].l-1]);    if (r<=tree[2*g].rr) return getmaxs(2*g,l,r);    else if (l>=tree[2*g+1].ll) return getmaxs(2*g+1,l,r);        else {            lret=getmaxs(2*g,l,tree[2*g].rr);            rret=getmaxs(2*g+1,tree[2*g+1].ll,r);            ret.lmax=max(lret.lmax,lret.sum+rret.lmax);            ret.rmax=max(rret.rmax,rret.sum+lret.rmax);            ret.mmax=max(lret.mmax,rret.mmax);            ret.mmax=max(ret.mmax,ret.lmax);            ret.mmax=max(ret.mmax,ret.rmax);            ret.mmax=max(ret.mmax,lret.rmax+rret.lmax);            return ret;        }}int main(){    int i,j,k,m,len;    node kk;    long long x,y;    scanf("%d%d", &k, &m);    for (i=1;i<=k;i++) {        scanf("%d", &n[i]);        for (j=1;j<=n[i];j++) scanf("%d", &a[i][j]);    }    for (i=1;i<=k;i++) build_tree(i,1,1,n[i]+1);    scanf("%s", &s);len=strlen(s);ssum[0]=0;for (i=0;i<len;i++) aa[i+1]=s[i]-'0'+1,ssum[i+1]=ssum[i]+n[aa[i+1]];    build_trees(1,1,len+1);while (m--) {        scanf("%lld%lld", &x, &y);        kk=getmaxs(1,x,y);        printf("%lld ", kk.mmax);}return 0;}
0 0
原创粉丝点击