1. 程式人生 > >COGS 775. 山海經 【線段樹】

COGS 775. 山海經 【線段樹】

hellip char 維護 targe ttr 問題 相等 -a str

775. 山海經

【問題描述】

“南山之首日鵲山。其首日招搖之山,臨於西海之上,多桂,多金玉。有草焉,其狀如韭而青華,其名日祝余,食之不饑……又東三百裏,日堂庭之山,多棪木,多白猿,多水玉,多黃金。

又東三百八十裏,日猨翼之山,其中多怪獸,水多怪魚,多白玉,多蝮蟲,多怪蛇,名怪木,不可以上。……”

《山海經》是以山為綱,以海為線記載古代的河流、植物、動物及礦產等情況,而且每一條記錄路線都不會有重復的山出現。某天,你的地理老師想重遊《山海經》中的路線,為了簡化問題,老師已經把每座山用一個整數表示他對該山的喜惡程度,他想知道第a座山到第b座山的中間某段路(i,j)。能使他感到最滿意,即(i,j)這條路上所有山的喜惡度之和是(c,d)(a≤c≤d≤b)最大值。於是老師便向你請教,你能幫助他嗎?值得註意的是,在《山海經》中,第i座山只能到達第i+1座山。

【輸入】

輸入第1行是兩個數,n,m,2≤n≤100000,1≤m≤100000,n表示一共有n座山,m表示老師想查詢的數目。

第2行是n個整數,代表n座山的喜惡度,絕對值均小於10000。

以下m行每行有a,b兩個數,1≤a≤j≤b≤m,表示第a座山到第b座山。

【輸出】

一共有m行,每行有3個數i,j,s,表示從第i座山到第j座山總的喜惡度為s。顯然,對於每個查詢,有a≤i≤j≤b,如果有多組解,則輸出i最小的,如果i也相等,則輸出j最小的解。

【輸入樣例】

5 3

5 -6 3 -1 4

1 3

1 5

5 5

【輸出樣例】

1 1 5

3 5 6

5 5 4

我感覺炒雞惡心 啊

線段樹維護十個域

常規 的 l r 代表此區間左右端點

ql qr 代表此區間連續子段最大的區間的左右端點

lr 代表從左端點 最大左子串能到達的位置

rl 代表從右端點 最大右子串能到達的位置

lm rm代表最大左子串和最大右子串

sum 代表區間和

mx代表區間最大連續子串

建樹更新,查詢也要更新

技術分享
  1 #include <cstdio>
  2 #include <cctype>
  3 
  4 const int MAXN=100010
; 5 6 int n,m; 7 8 struct SegmentTree { 9 int l,r; 10 int ql,qr,lr,rl; 11 int sum,lm,rm,mx; 12 }; 13 SegmentTree t[MAXN<<2]; 14 15 inline void read(int&x) { 16 int f=1;register char c=getchar(); 17 for(x=0;!isdigit(c);c==-&&(f=-1),c=getchar()); 18 for(;isdigit(c);x=x*10+c-48,c=getchar()); 19 x=x*f; 20 } 21 22 inline int max(int a,int b) {return a<b?b:a;} 23 24 inline void up(int now) { 25 t[now].sum=t[now<<1].sum+t[now<<1|1].sum; 26 27 t[now].lm=t[now<<1].lm; 28 t[now].lr=t[now<<1].lr; 29 if(t[now].lm<t[now<<1].sum+t[now<<1|1].lm) { 30 t[now].lm=t[now<<1].sum+t[now<<1|1].lm; 31 t[now].lr=t[now<<1|1].lr; 32 } 33 34 t[now].rm=t[now<<1|1].rm; 35 t[now].rl=t[now<<1|1].rl; 36 if(t[now].rm<=t[now<<1|1].sum+t[now<<1].rm) { 37 t[now].rm=t[now<<1|1].sum+t[now<<1].rm; 38 t[now].rl=t[now<<1].rl; 39 } 40 41 t[now].mx=t[now<<1].mx; 42 t[now].ql=t[now<<1].ql;t[now].qr=t[now<<1].qr; 43 if(t[now].mx<t[now<<1].rm+t[now<<1|1].lm) { 44 t[now].mx=t[now<<1].rm+t[now<<1|1].lm; 45 t[now].ql=t[now<<1].rl; 46 t[now].qr=t[now<<1|1].lr; 47 } 48 if(t[now].mx<t[now<<1|1].mx){ 49 t[now].mx=t[now<<1|1].mx; 50 t[now].ql=t[now<<1|1].ql; 51 t[now].qr=t[now<<1|1].qr; 52 } 53 return; 54 } 55 56 void build_tree(int now,int l,int r) { 57 t[now].l=l,t[now].r=r; 58 if(l==r) { 59 read(t[now].sum); 60 t[now].ql=t[now].qr=l; 61 t[now].lr=t[now].rl=l; 62 t[now].mx=t[now].lm=t[now].rm=t[now].sum; 63 return; 64 } 65 int mid=(l+r)>>1; 66 build_tree(now<<1,l,mid); 67 build_tree(now<<1|1,mid+1,r); 68 up(now); 69 } 70 71 SegmentTree query(int now,int l,int r) { 72 if(l==t[now].l&&r==t[now].r) return t[now]; 73 int mid=(t[now].l+t[now].r)>>1; 74 SegmentTree ls,rs,ans; 75 if(r<=mid) return query(now<<1,l,r); 76 else if(l>mid) return query(now<<1|1,l,r); 77 else { 78 ls=query(now<<1,l,mid); 79 rs=query(now<<1|1,mid+1,r); 80 ans.l=ls.l;ans.r=rs.r; 81 82 ans.lm=ls.lm;ans.lr=ls.lr; 83 if(ans.lm<ls.sum+rs.lm) { 84 ans.lm=ls.sum+rs.lm; 85 ans.lr=rs.lr; 86 } 87 88 ans.rm=rs.rm;ans.rl=rs.rl; 89 if(ans.rm<rs.sum+ls.rm) { 90 ans.rm=rs.sum+ls.rm; 91 ans.rl=ls.rl; 92 } 93 94 ans.sum=ls.sum+rs.sum; 95 ans.mx=ls.mx,ans.ql=ls.ql,ans.qr=ls.qr; 96 if(ls.rm+rs.lm>ans.mx) { 97 ans.mx=ls.rm+rs.lm; 98 ans.ql=ls.rl;ans.qr=rs.lr; 99 } 100 if(rs.mx>ans.mx) { 101 ans.mx=rs.mx; 102 ans.ql=rs.ql;ans.qr=rs.qr; 103 } 104 } 105 return ans; 106 } 107 108 int hh() { 109 freopen("hill.in","r",stdin); 110 freopen("hill.out","w",stdout); 111 read(n);read(m); 112 build_tree(1,1,n); 113 for(int x,y;m--;) { 114 read(x);read(y); 115 SegmentTree now=query(1,x,y); 116 printf("%d %d %d\n",now.ql,now.qr,now.mx); 117 } 118 return 0; 119 } 120 121 int sb=hh(); 122 int main(int argc,char**argv) {;}
代碼

COGS 775. 山海經 【線段樹】