1. 程式人生 > >uva 1400 "Ray, Pass me the dishes!" (區間合並 最大子段和+輸出左右邊界)

uva 1400 "Ray, Pass me the dishes!" (區間合並 最大子段和+輸出左右邊界)

scan fine 之前 邊界 數組 uil pro 我們 mem

題目鏈接:https://vjudge.net/problem/UVA-1400

題意:給一串序列,求最大子段,如果有多個,輸出字典序最小的那個的左右端點

思路:

之前寫過類似的,這個麻煩點需要輸出左右端點,我們直接再開幾個數組維護左右邊界就好了,因為pushup和查詢都需要合並操作,我們可以改下pushup傳的參數,讓查詢的時候也可以用pushup合並區間信息。

字典序最小的只要合並和查詢的時候都優先向左就好了。

實現代碼;

#include<bits/stdc++.h>
using namespace std;
#define lson l,m,rt<<1
#define
rson m+1,r,rt<<1|1 #define mid int m = (l + r) >> 1 #define ll long long const int M = 5e5+10; int n; ll a[M]; struct node{ ll lsum,rsum,sum,num; int lef,rig,lid,rid; }t[M<<2]; void pushup(node &k,node ls,node rs){ k.num = ls.num + rs.num; if(ls.lsum>=ls.num+rs.lsum) k.lsum
=ls.lsum,k.lid=ls.lid; else k.lsum=ls.num+rs.lsum,k.lid=rs.lid; if(rs.rsum>rs.num+ls.rsum) k.rsum=rs.rsum,k.rid=rs.rid; else k.rsum=rs.num+ls.rsum,k.rid=ls.rid; if(ls.sum>=max(rs.sum,ls.rsum+rs.lsum)) k.sum=ls.sum,k.lef=ls.lef,k.rig=ls.rig;
else{ if(ls.rsum+rs.lsum>=rs.sum) k.sum=ls.rsum+rs.lsum,k.lef=ls.rid,k.rig=rs.lid; else k.sum=rs.sum,k.lef=rs.lef,k.rig=rs.rig; } } void build(int l,int r,int rt){ if(l == r){ t[rt].lid=t[rt].rid=t[rt].lef=t[rt].rig=l; t[rt].sum=t[rt].num=t[rt].lsum=t[rt].rsum=a[l]; return ; } mid; build(lson); build(rson); pushup(t[rt],t[rt<<1],t[rt<<1|1]); } node query(int L,int R,int l,int r,int rt){ if(L <= l&&R >= r){ return t[rt]; } mid; if(R <= m) return query(L,R,lson); else if(L > m) return query(L,R,rson); else{ node ret; pushup(ret,query(L,R,lson),query(L,R,rson)); return ret; } } int main() { int cas = 1,m,l,r; while(scanf("%d%d",&n,&m)!=EOF){ memset(t,0,sizeof(t)); for(int i = 1;i <= n;i ++) scanf("%lld",&a[i]); build(1,n,1); printf("Case %d:\n",cas++); while(m--){ scanf("%d%d",&l,&r); node ans = query(l,r,1,n,1); printf("%d %d\n",ans.lef,ans.rig); } } return 0; }

uva 1400 "Ray, Pass me the dishes!" (區間合並 最大子段和+輸出左右邊界)