1. 程式人生 > >3999. [TJOI2015]旅遊【樹鏈剖分】

3999. [TJOI2015]旅遊【樹鏈剖分】

== urn ati hang script 線段樹 城市編號 turn esc

Description

為了提高智商,ZJY準備去往一個新世界去旅遊。這個世界的城市布局像一棵樹。每兩座城市之間只有一條路徑可 以互達。每座城市都有一種寶石,有一定的價格。ZJY為了賺取最高利益,她會選擇從A城市買入再轉手賣到B城市 。由於ZJY買寶石時經常賣萌,因而凡是ZJY路過的城市,這座城市的寶石價格會上漲。讓我們來算算ZJY旅遊完之 後能夠賺取的最大利潤。(如a城市寶石價格為v,則ZJY出售價格也為v)

Input

第一行輸入一個正整數N,表示城市個數。 接下來一行輸入N個正整數表示每座城市寶石的最初價格p,每個寶石的初始價格不超過100。 第三行開始連續輸入N-1行,每行有兩個數字x和y。表示x城市和y城市有一條路徑。城市編號從1開始。 下一行輸入一個整數Q,表示詢問次數。 接下來Q行,每行輸入三個正整數a,b,v,表示ZJY從a旅遊到b,城市寶石上漲v。 1≤ N≤50000, 1≤Q ≤50000

Output

對於每次詢問,輸出ZJY可能獲得的最大利潤,如果虧本則輸出0。

Sample Input

3
1 2 3
1 2
2 3
2
1 2 100
1 3 100

Sample Output

1
1
不拍一下還真不知道自己錯了不少細節
對拍+debug使我快樂
一開始把題給讀錯了……技術分享圖片
對於這個題,我們要做的就是查詢路徑上的最大差值(max-min)。
然後就很容易想到用樹鏈剖分維護。
不過這個是有限制的,即在路徑上,min必須出現在max前面。
怎麽辦呢?我們可以分兩種情況來考慮。
1、max,min出現在一段完整的重鏈中。這個我們可以用線段樹上的標記很好的維護。
維護一個ans1一個ans2,分別表示不同方向時這一段內的最大差值。(看一下pushup函數就懂了)
2、max,min出現在不同的鏈中
我們往上跳的時候,按順序記錄一下我們路徑經過的輕重鏈的信息。
跳完之後掃一遍更新答案即可。
細節挺多的反正我拍掛了很多次
  1 #include<iostream>
  2 #include<cstring>
  3 #include<cstdio>
  4 #include<queue>
  5 #define N (50000+100)
  6 using namespace std;
  7 
  8
struct segt{int val,add,max,min,ans1,ans2;}Segt[N<<2],refun[N]; 9 struct node{int to,next;}edge[N<<1]; 10 int n,m,a[N],u,v,l,ans; 11 int head[N],num_edge; 12 int Father[N],Depth[N],Son[N],Sum[N]; 13 int T_num[N],Tree[N],Top[N],dfs_num; 14 queue<segt>q[2]; 15 16 void add(int u,int v) 17 { 18 edge[++num_edge].to=v; 19 edge[num_edge].next=head[u]; 20 head[u]=num_edge; 21 } 22 23 void Dfs1(int x) 24 { 25 Sum[x]=1; 26 Depth[x]=Depth[Father[x]]+1; 27 for (int i=head[x]; i; i=edge[i].next) 28 if (edge[i].to!=Father[x]) 29 { 30 Father[edge[i].to]=x; 31 Dfs1(edge[i].to); 32 Sum[x]+=Sum[edge[i].to]; 33 if (!Son[x] || Sum[Son[x]]<Sum[edge[i].to]) 34 Son[x]=edge[i].to; 35 } 36 } 37 38 void Dfs2(int x,int pre) 39 { 40 T_num[x]=++dfs_num; 41 Tree[dfs_num]=a[x]; 42 Top[x]=pre; 43 if (Son[x]) Dfs2(Son[x],pre); 44 for (int i=head[x]; i; i=edge[i].next) 45 if (edge[i].to!=Father[x] && edge[i].to!=Son[x]) 46 Dfs2(edge[i].to,edge[i].to); 47 } 48 49 void Pushdown(int now,int l,int r) 50 { 51 if (Segt[now].add) 52 { 53 int mid=(l+r)>>1; 54 Segt[now<<1].add+=Segt[now].add; 55 Segt[now<<1].val+=Segt[now].add*(mid-l+1); 56 Segt[now<<1|1].add+=Segt[now].add; 57 Segt[now<<1|1].val+=Segt[now].add*(r-mid); 58 Segt[now<<1].max+=Segt[now].add; 59 Segt[now<<1].min+=Segt[now].add; 60 Segt[now<<1|1].max+=Segt[now].add; 61 Segt[now<<1|1].min+=Segt[now].add;//一開始max和min忘記更新*%……%&* 62 Segt[now].add=0; 63 } 64 } 65 66 segt Pushup(int x,segt ls,segt rs)//pushup返回類型改一下方便處理 67 { 68 segt now=Segt[x]; 69 now.val=ls.val+rs.val; 70 now.max=max(ls.max,rs.max); 71 now.min=min(ls.min,rs.min); 72 now.ans1=max(ls.ans1,rs.ans1); 73 now.ans1=max(now.ans1,rs.max-ls.min); 74 now.ans2=max(ls.ans2,rs.ans2); 75 now.ans2=max(now.ans2,ls.max-rs.min); 76 return now; 77 } 78 79 void Build(int now,int l,int r) 80 { 81 if (l==r){Segt[now].val=Segt[now].max=Segt[now].min=Tree[l];return;} 82 int mid=(l+r)>>1; 83 Build(now<<1,l,mid); Build(now<<1|1,mid+1,r); 84 Segt[now]=Pushup(now,Segt[now<<1],Segt[now<<1|1]); 85 } 86 87 void Update(int now,int l,int r,int l1,int r1,int k) 88 { 89 if (l>r1 || r<l1) return; 90 if (l1<=l && r<=r1) 91 { 92 Segt[now].val+=(r-l+1)*k; 93 Segt[now].add+=k; 94 Segt[now].max+=k; 95 Segt[now].min+=k; 96 return; 97 } 98 Pushdown(now,l,r); 99 int mid=(l+r)>>1; 100 Update(now<<1,l,mid,l1,r1,k);Update(now<<1|1,mid+1,r,l1,r1,k); 101 Segt[now]=Pushup(now,Segt[now<<1],Segt[now<<1|1]); 102 } 103 104 segt Query(int now,int l,int r,int l1,int r1) 105 { 106 if (l1<=l && r<=r1) 107 return Segt[now]; 108 Pushdown(now,l,r); 109 int mid=(l+r)>>1; 110 if (r1<=mid) return Query(now<<1,l,mid,l1,r1); 111 if (l1>=mid+1) return Query(now<<1|1,mid+1,r,l1,r1); 112 return Pushup(now,Query(now<<1,l,mid,l1,r1),Query(now<<1|1,mid+1,r,l1,r1)); 113 } 114 115 void Change(int x,int y,int k) 116 { 117 int fx=Top[x],fy=Top[y]; 118 while (fx!=fy) 119 { 120 if (Depth[fx]<Depth[fy]) 121 swap(x,y),swap(fx,fy); 122 Update(1,1,n,T_num[fx],T_num[x],k); 123 x=Father[fx],fx=Top[x]; 124 } 125 if (Depth[x]<Depth[y]) swap(x,y); 126 Update(1,1,n,T_num[y],T_num[x],k); 127 } 128 129 int Ask(int x,int y)//主要就是這個函數裏的問題,我開了兩個queue來記錄路徑。 130 { 131 int fx=Top[x],fy=Top[y]; 132 int now=0,ans=0,cnt=0,h=0,sum; 133 while (fx!=fy) 134 { 135 if (Depth[fx]<Depth[fy]) 136 swap(x,y),swap(fx,fy),now^=1; 137 segt no=Query(1,1,n,T_num[fx],T_num[x]); 138 q[now].push(no); cnt++; 139 ans=max(ans,now==1?no.ans1:no.ans2); 140 x=Father[fx],fx=Top[x]; 141 } 142 if (Depth[x]<Depth[y]) swap(x,y),now^=1; 143 segt no=Query(1,1,n,T_num[y],T_num[x]); 144 ans=max(ans,now==1?no.ans1:no.ans2); 145 q[now].push(no); cnt++; 146 sum=cnt; 147 148 while (!q[0].empty()) refun[++h]=q[0].front(),q[0].pop(); 149 while (!q[1].empty()) refun[cnt--]=q[1].front(),q[1].pop(); 150 int minn=refun[1].min; 151 for (int i=2; i<=sum; ++i)//掃一遍路徑上的鏈,然後更新一下。 152 { 153 ans=max(ans,refun[i].max-minn); 154 minn=min(minn,refun[i].min);//一開始這裏忘了更新了#¥%#¥*& 155 } 156 return ans; 157 } 158 159 int main() 160 { 161 scanf("%d",&n); 162 for (int i=1; i<=n; ++i) 163 scanf("%d",&a[i]); 164 for (int i=1; i<=n-1; ++i) 165 { 166 scanf("%d%d",&u,&v); 167 add(u,v); add(v,u); 168 } 169 Dfs1(1); Dfs2(1,1); 170 Build(1,1,n); 171 scanf("%d",&m); 172 for (int i=1; i<=m; ++i) 173 { 174 scanf("%d%d%d",&u,&v,&l); 175 int ans=Ask(u,v); 176 printf("%d\n",ans>0?ans:0); 177 Change(u,v,l); 178 } 179 }

3999. [TJOI2015]旅遊【樹鏈剖分】