This article is made by Jason-Cow.Welcome to reprint.But please post the writer's address.
[NOIP2015]运输计划 Hello!链剖。你好吗?
题意:
给出一棵n个节点的带权树,m对树上点对
现在允许删除一条边,(权值修改为0)
输出: 最小化的点对间最大距离
1.链剖
2.树上差分
3.二分
链剖我就不多说了,就是两dfs
注意:要在dfs1中多维护一个dis[x],x到root的距离,顺便记录一下w[x]!
1 void dfs1(int u,int f){ 2 fa[u]=f,dep[u]=dep[f]+1,siz[u]=1; 3 for(int i=head[u];i;i=E[i].next){ 4 int v=E[i].v; 5 if(v!=f){ 6 w[v]=E[i].w,dis[v]=dis[u]+E[i].w; 7 dfs1(v,u); 8 siz[u]+=siz[v]; 9 if(!son[u]||siz[v]>siz[son[u]])son[u]=v;10 }11 }12 }
dfs1
1 void dfs2(int u,int t){2 dfn[u]=++idx,top[u]=t;3 if(son[u])dfs2(son[u],t);4 for(int i=head[u];i;i=E[i].next){5 int v=E[i].v;6 if(v!=fa[u]&&v!=son[u])dfs2(v,v);7 }8 }
dfs2
树上差分,先差分,后dfs上放(95分的根本原因,不过好写)
细节:add(l,r) <=> cf[l]++ , cf[r+1]--; 再上放
1 void modify(int u,int f){2 for(int i=head[u];i;i=E[i].next){3 int v=E[i].v;4 if(v!=f){5 modify(v,u);6 cf[u]+=cf[v];7 }8 }9 }
modify
二分,很显然好吗。
1 bool check(int x){ 2 int cnt=0,maxcost=0; 3 memset(cf,0,sizeof(cf)); 4 for(int i=1;i<=m;i++) 5 if(a[i].dis>x){ 6 cnt++; 7 maxcost=max(maxcost,a[i].dis-x); 8 cf[a[i].s]++,cf[a[i].t]++;cf[a[i].lca]-=2; 9 }10 if(cnt==0)return false;11 modify(1,0);12 for(int i=1;i<=n;i++)13 if(cf[i]==cnt && w[i]>=maxcost)14 return false;15 return true;16 }
check
这个还不是正解,因为被卡常了,于是我就卡数据,嘿嘿嘿~~
1 #include 2 #include 3 #include 4 #include 5 #include 6 #include 7 #include 8 #include 9 #include