【SOJ1136】【cogs775】山海经
2015-08-23 20:35
363 查看
Description
“南山之首日鹊山。其首日招摇之山,临于西海之上,多桂,多金玉。有草焉,其状如韭而青华,其名日祝余,食之不饥……又东三百里,日堂庭之山,多棪木,多白猿,多水玉,多黄金。又东三百八十里,日猨翼之山,其中多怪兽,水多怪鱼,多白玉,多蝮虫,多怪蛇,名怪木,不可以上。……”
《山海经》是以山为纲,以海为线记载古代的河流、植物、动物及矿产等情况,而且每一条记录路线都不会有重复的山出现。某天,你的地理老师海东想重游《山海经》中的路线,为了简化问题,海东老师已经把每座山用一个整数表示他对该山的喜恶程度,他想知道第a座山到第b座山的中间某段路(i,j)。能使他感到最满意,即(i,j)这条路上所有山的喜恶度之和是(c,d)(a≤c≤d≤b)最大值。于是老师便向你请教,你能帮助他吗?值得注意的是,在《山海经》中,第i座山只能到达第i+1座山。
Input
输入文件名为(hill.in)。输入第1行是两个数,n,m,2≤n≤100000,1≤m≤l00000,n表示一共有n座山,m表示老师想查询的数目。
第2行是n个整数,代表n座山的喜恶度,绝对值均小于10000。
以下m行每行有a,b两个数,1≤a≤j≤b≤m,表示第a座山到第b座山。
Output
输出文件名为(hill.out)。一共有m行,每行有3个数i,j,s,表示从第i座山到第j座山总的喜恶度为s。显然,对于每个查询,有a≤i≤j≤b,如果有多组解,则输出i最小的,如果i也相等,则输出j最小的解。
Sample Input
5 3 5 -6 3 -1 4 1 3 1 5 5 5
Sample Output
1 1 5 3 5 6 5 5 4
Hint
对于 30% 的数据,满足1<=n ,m<=500。 对于 60% 的数据,满足1<=n ,m<=2000。 对于 100% 的数据,满足1<=n ,m<=100000。
Key To Problem
60% 的数据,利用dp思想,对于每次询问查询一次区间最大连续子段和,时间复杂度为O(n*m);100% 的数据,可以用线段树来求。
建线段树时,需要考虑两个问题,线段树中储存的内容和如何利用子节点的信息来更新父节点的信息。
线段树中的内容不难想到需要利用三个值来求解。
一开始我想的是cnt表示一个节点最大值区间,lcnt表示节点中最大区间左边所有值的和,rcnt表示节点中最大区间右边所有值的和。好不容易写出来了,之后我就傻逼了,这个奇怪的东西连样例都过不了。
于是我就想啊想,想啊想,终于搞出来一个更奇怪的东西。
lcnt--表示从左边起的最大连续喜恶度之和; rcnt——表示从右边起的最大连续喜恶度之和; cnt--表示节点中最大连续喜恶度之和;
当然,为了标记cnt,我们还需要几个东西:
rleft--表示lcnt的右端点; lright--表示rcnt的左端点; l--表示cnt的左端点; r--表示cnt的右端点;
之后就是更新的问题,这个显然就好想多了
rt.lcnt=max(ls.lcnt,sum[ls]+rs.cnt); rt.cnt=max(ls.cnt,rs.cnt,ls.rcnt+rs.lcnt); rt.rcnt=max(ls.rcnt+sum[rs],rs.rcnt);
询问和更新差不多,对于一个父节点,如果只用了它的左节点或右节点,那么只返回左节点或右节点就可以了,当左右节点都用到的时候,与更新相同。
CODE
#include<cstdio> #include<cstring> #include<algorithm> #define N 100010 #define lson l,mid,rt<<1 #define rson mid+1,r,rt<<1|1 #define ls rt<<1 #define rs rt<<1|1 using namespace std; struct node { int lcnt,rcnt,cnt,rleft,lright,l,r; }; int f[N<<2]; node p[N<<2]; int n,m; void PushUp(node &a,node &b,node &s,int rt) { f[rt]=f[ls]+f[rs]; if(a.lcnt>=f[ls]+b.lcnt) { s.rleft=a.rleft; s.lcnt=a.lcnt; }else { s.rleft=b.rleft; s.lcnt=f[ls]+b.lcnt; } if(a.cnt>=b.cnt&&a.cnt>=a.rcnt+b.lcnt) { s.l=a.l,s.r=a.r; s.cnt=a.cnt; }else if(a.rcnt+b.lcnt>a.cnt&&a.rcnt+b.lcnt>=b.cnt) { s.l=a.lright,s.r=b.rleft; s.cnt=a.rcnt+b.lcnt; }else { s.l=b.l,s.r=b.r; s.cnt=b.cnt; } if(a.rcnt+f[rs]>=b.rcnt) { s.lright=a.lright; s.rcnt=a.rcnt+f[rs]; }else { s.lright=b.lright; s.rcnt=b.rcnt; } } void build(int l,int r,int rt) { if(l==r) { scanf("%d",&f[rt]); p[rt].lcnt=p[rt].rcnt=p[rt].cnt=f[rt]; p[rt].lright=p[rt].l=l; p[rt].rleft=p[rt].r=r; return ; } int mid=(l+r)>>1; build(lson); build(rson); PushUp(p[ls],p[rs],p[rt],rt); } node query(int L,int R,int l,int r,int rt) { if(l>=L&&r<=R) return p[rt]; int mid=(l+r)>>1; node a,b,s; if(mid>=L) a=query(L,R,lson); if(mid<R) b=query(L,R,rson); if(mid>=R) return a; if(mid<L) return b; PushUp(a,b,s,rt); return s; } int main() { // freopen("hill.in","r",stdin); // freopen("hill.out","w",stdout); scanf("%d%d",&n,&m); build(1,n,1); for(int i=1;i<=m;i++) { int x,y; scanf("%d%d",&x,&y); node ans=query(x,y,1,n,1); printf("%d %d %d\n",ans.l,ans.r,ans.cnt); } return 0; }
相关文章推荐
- 线段树题集
- soj1005. Roll Playing Games
- soj1041. Pushing Boxes
- hdu1754
- HDU1394
- 敌兵布阵 (1)
- I Hate It (1)
- LCIS (2)
- A Simple Problem with Integers (2)
- Mayor's posters (3)
- Buy Tickets (3)
- 线段树
- UVA - 12532 Interval Product
- POJ 3264 Balanced Lineup
- hdu 1542 求矩形并的面积
- 关于数据结构之线段树
- poj 3225 关于集合运算
- poj 2352
- hdu1166敌兵布阵(线段树点修改)
- POJ 2352 Stars 线段树 pascal