bzoj4326: NOIP2015 运输计划(lca+二分)
来源:互联网 发布:使用sql语句创建用户 编辑:程序博客网 时间:2024/05/17 01:00
题目传送门
好题啊。
解法:
比较综合。。
我一开始想:
先把所有距离求出来。
然后二分答案。
所有的路径距离>答案 说明需要建虫洞。
在所有大于答案的路径中是有交集的。
那么我们只需要在交集中找到一条边使得所有路径-边权<=答案。
然后用差分咯。
sum[i]表示1到i这条边次数都加1。
然后就差分嘛。
对于每个x和y。
1到x路径+1
1到y路径+1
1到lca路径-2就行了嘛。
代码实现:
#include<cstdio>#include<cstring>#include<cstdlib>#include<iostream>#include<algorithm>#include<cmath>#include<queue>using namespace std;struct node {int x,y,c,next;}a[2100000];int len,last[1100000];void ins(int x,int y,int c) {len++;a[len].x=x;a[len].y=y;a[len].c=c;a[len].next=last[x];last[x]=len;}int n,m,mn[21][610000],dfn,dep[1100000],ys[1100000],bin[21],dist[1100000],Lca[1100000],to[1100000];//ys表示与父亲的边权 void dfs(int x) { for(int k=last[x];k;k=a[k].next) { int y=a[k].y; if(y!=mn[0][x]) {mn[0][y]=x;dep[y]=dep[x]+1;ys[y]=a[k].c;to[y]=to[x]+a[k].c;dfs(y);} }}void work() { bin[0]=1;for(int i=1;i<=20;i++)bin[i]=bin[i-1]*2; for(int j=1;j<=20;j++)for(int i=1;i<=n;i++)if(dep[i]>=bin[j])mn[j][i]=mn[j-1][mn[j-1][i]];}int lca(int x,int y) { if(dep[x]>dep[y])swap(x,y); for(int i=20;i>=0;i--)if(dep[y]-dep[x]>=bin[i])y=mn[i][y]; if(x==y)return x; for(int i=20;i>=0;i--)if(mn[i][y]!=mn[i][x]&&dep[x]>=bin[i]){x=mn[i][x];y=mn[i][y];} return mn[0][x];}int xx[1100000],yy[1100000],sum[1100000];void cf(int x) { for(int k=last[x];k;k=a[k].next) { int y=a[k].y; if(y!=mn[0][x]) {cf(y);sum[x]+=sum[y];} }}int main() { scanf("%d%d",&n,&m);len=0;memset(last,0,sizeof(last)); for(int i=1;i<n;i++) {int x,y,c;scanf("%d%d%d",&x,&y,&c);ins(x,y,c);ins(y,x,c);} mn[0][1]=0;dep[1]=0;ys[1]=0;to[1]=0;dfs(1);work(); int l=1,r=0,mid,ans=0; for(int i=1;i<=m;i++) { scanf("%d%d",&xx[i],&yy[i]);Lca[i]=lca(xx[i],yy[i]); dist[i]=to[xx[i]]+to[yy[i]]-2*to[Lca[i]];r=max(r,dist[i]); } while(l<=r) { mid=(l+r)/2;int mmax=0,tot=0;memset(sum,0,sizeof(sum)); for(int i=1;i<=m;i++)if(dist[i]>mid) { tot++;mmax=max(mmax,dist[i]-mid);sum[xx[i]]++;sum[yy[i]]++;sum[Lca[i]]-=2; }cf(1); bool bk=false; for(int i=1;i<=n;i++)if(sum[i]>=tot&&ys[i]>=mmax) {bk=true;break;} if(bk==true) {r=mid-1;ans=mid;} else l=mid+1; } printf("%d\n",ans); return 0;}
阅读全文