[Noip2015]運輸計劃
阿新 • • 發佈:2020-08-15
[Noip2015]運輸計劃
一.前言
阿這……我已經儘量把常數些小了,題目光明正大地卡常,sort自身就很魔幻……題目連結
二.思路
快快樂樂二分做法。可以直接二分時間,是滿足性質的。對於每一個猜想mid?反正進行check的時候找出所有的時間大於 mid 的計劃,然後找出有哪些道路(長度設為 u)是同時被所有計劃經過,並且刪掉以後滿足 \(mid+u>=計劃時間_{max}\),就很暴力……
關於道路經過數……可以差分做一個自下往上的字首和(一個點被經過的次數也是點連父親的那條邊被經過的次數),將計劃起終點的字首和 +1 ,在 lca 處減 2,做字首和就可以得到經過次數(推薦手玩理解)
做字首和的時候順便判刪邊就好。
三.CODE
#include<iostream> #include<cstdio> #include<algorithm> #include<fstream> #include<cmath> #include<cstring> using namespace std; int read(){ char ch=getchar(); int res=0,f=1; for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1; for(;ch>='0'&&ch<='9';ch=getchar())res=res*10+(ch-'0'); return res*f; } const int MAXN=300005; int n,m,ans=1; int head[MAXN],ne[2*MAXN],to[2*MAXN],dis[2*MAXN],tot; void add(int x,int y,int z){to[++tot]=y,dis[tot]=z,ne[tot]=head[x],head[x]=tot;} int dep[MAXN],f[MAXN][20],fdis[MAXN][20]; void dfs(int x,int fa){ dep[x]=dep[fa]+1; f[x][0]=fa; for(int i=1;i<20;++i) f[x][i]=f[f[x][i-1]][i-1],fdis[x][i]=fdis[x][i-1]+fdis[f[x][i-1]][i-1]; for(int i=head[x];i;i=ne[i]){ if(to[i]==fa)continue; fdis[to[i]][0]=dis[i]; dfs(to[i],x); } } inline int LCA(int x,int y,int &u){ int cnt=0; if(dep[x]<dep[y])swap(x,y); for(int i=19;i>=0;--i)if(dep[f[x][i]]>=dep[y])cnt+=fdis[x][i],x=f[x][i]; if(x==y){ u=x; return cnt; } for(int i=19;i>=0;--i)if(f[x][i]!=f[y][i]) cnt+=fdis[x][i]+fdis[y][i],x=f[x][i],y=f[y][i]; u=f[x][0]; return cnt+fdis[x][0]+fdis[y][0]; } struct road{ int s,t,alf,lca; }r[MAXN]; bool cmp(road x,road y){ return x.alf>y.alf; } int sum[MAXN],u,cnt; bool fl; void solve(int x,int fa){ for(int i=head[x];i;i=ne[i]){ if(to[i]==fa)continue; solve(to[i],x); sum[x]+=sum[to[i]]; sum[to[i]]=0; } if(sum[x]==cnt&&x!=1&&fdis[x][0]>=u)fl=1; } bool check(int x){ u=r[1].alf-x,cnt=0; for(int i=1;i<=m;++i){ if(r[i].alf<=x)break; cnt++,sum[r[i].s]++,sum[r[i].t]++,sum[r[i].lca]-=2; } fl=0; solve(1,0);sum[1]=0; return fl; } int main(){ n=read();m=read(); for(int i=1,x,y,z;i<n;++i){ x=read();y=read();z=read(); add(x,y,z);add(y,x,z); } dfs(1,0); for(int i=1;i<=m;++i){ r[i].s=read();r[i].t=read(); r[i].alf=LCA(r[i].s,r[i].t,r[i].lca); } sort(r+1,r+m+1,cmp); int L=0,R=r[1].alf; while(L<=R){ int mid=(L+R)>>1; if(check(mid)){ ans=mid,R=mid-1; } else L=mid+1; } printf("%d",ans); return 0; }