1. 程式人生 > >NOIP2015 運輸計劃 (樹上差分+二分答案)

NOIP2015 運輸計劃 (樹上差分+二分答案)

!= int continue 卡常 class 其中 記錄 oid 差分

---恢復內容開始---

題目大意:給你一顆樹,你可以把其中一條邊的邊權改成0,使給定的一些樹鏈的權值和的最大值最小

把lenth定義為未修改邊權時的答案

考慮二分答案,如果二分的答案成立,設修改成0的邊邊權為k,那麽所有原鏈長>mid的鏈都要被這條邊影響,顯然這些鏈存在邊權為k的公共邊

那麽我們二分出一個答案,然後把所有原鏈長>mid的鏈在樹上打差分來記錄每條邊被覆蓋多少次

如果某條邊的滿足lenth-邊權<=mid 且 這條邊被覆蓋次數==原鏈長>mid的鏈數,說明這條邊作為0邊可行。

會卡常,據說樹剖不會被卡但我用了結果還是被卡了。懶得優化了

  1 #include <cstdio>
  2
#include <algorithm> 3 #include <cstring> 4 #define N 300100 5 using namespace std; 6 7 int n,m,cte,mxl,cnt,lth,ct,idd; 8 int head[N],sz[N],tp[N],hvy[N],fa[N],dep[N],dif[N],sum[N],d[N],dis[N]; 9 struct EDGE{ 10 int to,nxt,val; 11 }edge[N*2]; 12 struct FLY{ 13 int x,y,ff,len;
14 }fly[N]; 15 void edge_add(int u,int v,int w) 16 { 17 cte++; 18 edge[cte].to = v; 19 edge[cte].nxt= head[u]; 20 edge[cte].val= w; 21 head[u]=cte; 22 } 23 int gc() 24 { 25 int rett=0,fh=1;char p=getchar(); 26 while(p<0||p>9) {p=getchar();} 27 while
(p>=0&&p<=9) {rett=rett*10+p-0;p=getchar();} 28 return rett*fh; 29 } 30 void dfs_order1(int u,int dad) 31 { 32 int h=0,id=0; 33 for(int j=head[u];j!=-1;j=edge[j].nxt) 34 { 35 int v=edge[j].to; 36 if(v==dad) continue; 37 dis[v]=dis[u]+edge[j].val; 38 dep[v]=dep[u]+1; 39 dfs_order1(v,u); 40 d[v]=edge[j].val; 41 fa[v]=u; 42 if(sz[v]>h) h=sz[v],id=v; 43 sz[u]+=sz[v]; 44 } 45 sz[u]++; 46 if(head[u]==-1) return; 47 hvy[u]=id; 48 } 49 void dfs_order2(int u,int dad,int tpp) 50 { 51 tp[u]=tpp; 52 if(hvy[u]) tp[hvy[u]]=tp[u],dfs_order2(hvy[u],u,tpp); 53 for(int j=head[u];j!=-1;j=edge[j].nxt) 54 { 55 int v=edge[j].to; 56 if(v==dad||v==hvy[u]) continue; 57 dfs_order2(v,u,v); 58 } 59 } 60 void dfs_maxlenth(int u,int dad) 61 { 62 sum[u]+=dif[u]; 63 for(int j=head[u];j!=-1;j=edge[j].nxt) 64 { 65 int v=edge[j].to; 66 if(v==dad) continue; 67 dfs_maxlenth(v,u); 68 sum[u]+=sum[v]; 69 } 70 if(sum[u]>=ct&&d[u]>mxl) idd=u,mxl=d[u]; 71 } 72 int LCA(int x,int y) 73 { 74 while(tp[x]!=tp[y]) 75 { 76 if(dep[tp[x]]<dep[tp[y]]) swap(x,y); 77 x=fa[tp[x]]; 78 } 79 return dep[x]<=dep[y]?x:y; 80 } 81 bool check(int mid) 82 { 83 memset(sum,0,sizeof(sum)); 84 mxl=0,ct=0;; 85 for(int i=1;i<=m;i++) 86 if(fly[i].len>mid) 87 { 88 sum[fly[i].x]++,sum[fly[i].y]++; 89 sum[fly[i].ff]-=2; 90 ct++; 91 } 92 dfs_maxlenth(1,-1); 93 if(lth-mxl<=mid) return 1; 94 else return 0; 95 } 96 97 int main() 98 { 99 //freopen("testdata.in","r",stdin); 100 scanf("%d%d",&n,&m); 101 memset(head,-1,sizeof(head)); 102 int x,y,z; 103 for(int i=1;i<n;i++) 104 { 105 x=gc(),y=gc(),z=gc(); 106 edge_add(x,y,z); 107 edge_add(y,x,z); 108 } 109 dfs_order1(1,-1); 110 tp[1]=1; 111 dfs_order2(1,-1,1); 112 lth=0; 113 for(int i=1;i<=m;i++) 114 { 115 fly[i].x=gc(),fly[i].y=gc(); 116 fly[i].ff=LCA(fly[i].x,fly[i].y); 117 fly[i].len=dis[fly[i].x]+dis[fly[i].y]-2*dis[fly[i].ff]; 118 lth=max(lth,fly[i].len); 119 } 120 int l=0,r=0; 121 r=lth; 122 int ret=0; 123 while(l<r) 124 { 125 int mid=(l+r)>>1; 126 if(check(mid)) r=mid,ret=mid; 127 else l=mid+1; 128 } 129 printf("%d",ret); 130 return 0; 131 }

---恢復內容結束---

NOIP2015 運輸計劃 (樹上差分+二分答案)