最大连续子序和 (加强版?)
2015-02-11 21:38
127 查看
题目描述 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;
给你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; }
相关文章推荐
- HDU 1003 Max Sum (最大连续子序和)
- HDU1003 最大连续子序和 DP
- hdu1003 最大连续子序和
- HDU-1003最大连续子序和
- HDU1003 Max Sum(最大连续子序和、贪心、DP)
- 最大连续子序和
- hdu1003 最大连续子序和
- 程序员面试金典——最大连续数列和___
- 面试题31:连续子数组的最大和
- 求数组中连续最大和
- [剑指offer]连续子数组的最大和
- HDU 4561 金山居 连续最大积
- 找出给定数数组里连续的元素和的最大值
- [LeetCode] Maximum Product Subarray 连续数列最大积
- 方格连续置1面积最大值
- 欧拉计划之题目8:找出这个1000位数字中连续5个数字乘积的最大值
- 《一道笔试题》找出最连续数字的最大长度
- 百度面试题——最大连续数字串问题
- 连续最大积
- 【codeforces 722C】【逆向思维 离线+并查集】C. Destroying Array 【给你n个数,每次摧毁一个,求每摧毁一个的最大连续和(被摧毁的点的两边不连续)】