NOIP2015_提高组Day2_3_运输计划
这题思路很简单;
先对每个询问求距离,对距离由大到小排序,
二分最小距离,验证是否可行,验证时用差分处理;
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<iostream> #include<cstring> #include<cstdio> #include<cstdlib> #include<algorithm> #include<iomanip> #include<map> #include<set> #include<vector> #include<ctime> #include<cmath> #define LL long long using namespace std; #define LL long long #define up(i,j,n) for(int i=(j);(i)<=(n);(i)++) #define max(x,y) ((x)<(y)?(y):(x)) #define min(x,y) ((x)<(y)?(x):(y)) #define FILE "1" #define pii pair<int,int> const int maxn=303000,inf=1000000000; int read(){ int x=0;bool flag=0;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')flag=1;ch=getchar();} while(ch<='9'&&ch>='0'){x=x*10+ch-'0';ch=getchar();} return flag?-x:x; } int n,m; struct node{ int y,next,v; }e[maxn<<1]; int linkk[maxn],len=0,fa[maxn],w[maxn],dep[maxn],top[maxn],siz[maxn],son[maxn],d[maxn]; void insert(int x,int y,int v){ e[++len].y=y; e[len].v=v; e[len].next=linkk[x]; linkk[x]=len; } int q[maxn],tail=0,head=0; void dfs(int x){ siz[x]=1; for(int i=linkk[x];i;i=e[i].next){ if(e[i].y==fa[x])continue; fa[e[i].y]=x;w[e[i].y]=e[i].v;dep[e[i].y]=dep[x]+1; dfs(e[i].y); siz[x]+=siz[e[i].y]; if(siz[e[i].y]>siz[son[x]])son[x]=e[i].y; } } void dfs2(int x){ if(son[x]){ top[son[x]]=top[x]; d[son[x]]=d[x]+w[son[x]]; dfs2(son[x]); } for(int i=linkk[x];i;i=e[i].next){ if(e[i].y==fa[x]||e[i].y==son[x])continue; top[e[i].y]=e[i].y; d[e[i].y]=0; dfs2(e[i].y); } } pii lca(int x,int y){ int u,v; int sum=0; while(x!=y){ u=top[x],v=top[y]; if(u==v)return make_pair((dep[x]>dep[y]?y:x),sum+abs(d[x]-d[y])); if(dep[u]>dep[v]){swap(x,y);swap(u,v);} sum+=d[y]+w[v]; y=fa[v]; } return make_pair(x,sum); } struct Node{ int x,y,v,f; bool operator<(const Node &b)const{return v>b.v;} }a[maxn]; int vis[maxn]; int maxx=0,flag=0; void Dfs(int x){ for(int i=linkk[x];i;i=e[i].next){ if(e[i].y==fa[x])continue; Dfs(e[i].y); vis[x]+=vis[e[i].y]; } if(vis[x]==flag)maxx=max(maxx,w[x]); } int work(int mid){ memset(vis,0,sizeof(vis)); for(int i=1;i<=mid;i++)vis[a[i].x]++,vis[a[i].y]++,vis[a[i].f]-=2;//比较暴力的差分 //可以利用树链剖分将树划分成线段,在上面做差分,常数要比这个小的多,实测结果是#20会超 maxx=0;flag=mid;Dfs(1); return maxx; } void slove(){ n=read();m=read(); int x,y,v; up(i,2,n){ x=read(),y=read(),v=read(); insert(x,y,v);insert(y,x,v); } dfs(1);top[1]=1; dfs2(1); pii temp; up(i,1,m){ a[i].x=read(),a[i].y=read(); temp=lca(a[i].x,a[i].y); a[i].v=temp.second;a[i].f=temp.first; } sort(a+1,a+m+1); int left=1,right=m,mid,ans=inf;//也可以1-a[1].v这样枚举,加个记忆化就好; while(left<=right){ mid=(left+right)>>1; int fee=a[1].v-work(mid); if(fee>a[mid+1].v)right=mid-1; else left=mid+1; ans=min(ans,max(fee,a[mid+1].v)); } cout<<ans<<endl; } int main(){ freopen(FILE".in","r",stdin); freopen(FILE".out","w",stdout); slove(); return 0; } //如果window下评测注意加个开栈