1. 程式人生 > >BZOJ 4326 NOIP 2015 DAY2 T3 淺談二分及樹上差分陣列DFS動態統計

BZOJ 4326 NOIP 2015 DAY2 T3 淺談二分及樹上差分陣列DFS動態統計

這裡寫圖片描述
世界真的很大
今天正值全校運動會然而卻被困機房
想著寫完這道題就下樓看運動會於是乎一A,老天luogu的“大凶”能奈我何?
於是還剩一點時間,所以寫一下部落格

看題先:

description:

公元 2044 年,人類進入了宇宙紀元。L 國有 n 個星球,還有 n−1 條雙向航道,每條航道建立在兩個星球之間,這 n−1 條航道連通了 L 國的所有星球。小 P 掌管一家物流公司, 該公司有很多個運輸計劃,每個運輸計劃形如:有一艘物流飛船需要從 ui 號星球沿最快的宇航路徑飛行到 vi 號星球去。顯然,飛船駛過一條航道是需要時間的,對於航道 j,任意飛船駛過它所花費的時間為 tj,並且任意兩艘飛船之間不會產生任何干擾。為了鼓勵科技創新, L 國國王同意小 P 的物流公司參與 L 國的航道建設,即允許小P 把某一條航道改造成蟲洞,飛船駛過蟲洞不消耗時間。在蟲洞的建設完成前小 P 的物流公司就預接了 m 個運輸計劃。在蟲洞建設完成後,這 m 個運輸計劃會同時開始,所有飛船一起出發。當這 m 個運輸計劃都完成時,小 P 的物流公司的階段性工作就完成了。如果小 P 可以自由選擇將哪一條航道改造成蟲洞, 試求出小 P 的物流公司完成階段性工作所需要的最短時間是多少?

input:

第一行包括兩個正整數 n,m,表示 L 國中星球的數量及小 P 公司預接的運輸計劃的數量,星球從 1 到 n 編號。接下來 n−1 行描述航道的建設情況,其中第 i 行包含三個整數 ai,bi 和 ti,表示第 i 條雙向航道修建在 ai 與 bi 兩個星球之間,任意飛船駛過它所花費的時間為 ti。資料保證 1≤ai,bi≤n 且 0≤ti≤1000。接下來 m 行描述運輸計劃的情況,其中第 j 行包含兩個正整數 uj 和 vj,表示第 j 個運輸計劃是從 uj 號星球飛往 vj號星球。資料保證 1≤ui,vi≤n

output:

輸出檔案只包含一個整數,表示小 P 的物流公司完成階段性工作所需要的最短時間。

所有時間取決於路徑的最大時間,時間最小就是說最大的時間最小
最大的最小,想到二分
二分一個最大值然後check
就是說找到一條邊刪掉之後能讓所有長度大於二分值的路徑小於二分值
就是說這條邊被所有路徑經過
一個差分陣列統計每個點頭上的那條邊被多少個路徑經過
u++,v++,lca-=2
然後在所有這樣的路徑裡面選一條值最大的
看所有路徑的最大值減去這個值之後能不能滿足條件

思路還是比較清晰而且好寫好調

完整程式碼:

#include<stdio.h>
#include<algorithm>
#include<cstring>
using
namespace std; struct edge { int v,last,w,u; }ed[600010],csn[300010]; int n,m,num=0; int head[300010],src[300010],dis[300010]; int dep[300010],anc[300010][20],mrk[300010]; bool cmp(const edge &a,const edge &b) { return a.w<b.w; } void add(int u,int v,int w) { num++; ed[num].v=v; ed[num].w=w; ed[num].last=head[u]; head[u]=num; } void dfs(int u,int f) { anc[u][0]=f; for(int i=1;i<=18;i++) anc[u][i]=anc[anc[u][i-1]][i-1]; for(int i=head[u];i;i=ed[i].last) { int v=ed[i].v; if(v==f) continue ; dis[v]=dis[u]+ed[i].w,dep[v]=dep[u]+1,src[v]=ed[i].w; dfs(v,u); } } int lca(int u,int v) { if(dep[u]<dep[v]) swap(u,v); for(int i=18;i>=0;i--) if(dep[anc[u][i]]>=dep[v]) u=anc[u][i]; if(u==v) return u; for(int i=18;i>=0;i--) if(anc[u][i]!=anc[v][i]) u=anc[u][i],v=anc[v][i]; return anc[u][0]; } void dfs2(int u,int f) { for(int i=head[u];i;i=ed[i].last) { int v=ed[i].v; if(v==f) continue ; dfs2(v,u); mrk[u]+=mrk[v]; } } bool check(int x) { memset(mrk,0,sizeof(mrk)); int cnt=0,bns=-1; for(int i=m;i>=1;i--) { if(csn[i].w<=x) break ; cnt++; mrk[csn[i].u]++,mrk[csn[i].v]++; mrk[lca(csn[i].u,csn[i].v)]-=2; } dfs2(1,1); for(int i=1;i<=n;i++) if(mrk[i]==cnt) bns=max(bns,src[i]); if(csn[m].w-bns>x) return false; return true ; } int main() { scanf("%d%d",&n,&m); for(int i=1;i<n;i++) { int u,v,w; scanf("%d%d%d",&u,&v,&w); add(u,v,w),add(v,u,w); } dfs(1,1); int lf=0,rg=0,ans=0; for(int i=1;i<=m;i++) { int u,v; scanf("%d%d",&u,&v); csn[i].u=u,csn[i].v=v; csn[i].w=dis[u]+dis[v]-2*dis[lca(u,v)]; rg=max(rg,csn[i].w); } sort(csn+1,csn+m+1,cmp); while(lf<=rg) { int mid=(lf+rg)>>1; if(check(mid)) rg=mid-1,ans=mid; else lf=mid+1; } printf("%d\n",ans); return 0; } /* Whoso pulleth out this sword from this stone and anvil is duly born King of all England */

嗯,就是這樣