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;}
阅读全文
'); })();
0 0
原创粉丝点击
热门IT博客
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 黄石旅游 黄石寨 黄石招聘 黄石社保 黄石火车站 黄石到武汉 黄石美剧 黄石人事 黄石北站 黄石论坛 黄石第一季 黄石特产 黄石港 黄石信息网 黄石在哪 黄石找工作 黄石楼盘 黄石房产 黄石人 黄石是哪里 黄石装修网 黄石在哪里 湖北黄石市 黄石大学 黄石万达 黄石招聘网 黄石怎么样 黄石公交 黄石信息 黄石吧 黄石房产网 黄石信息港 黄石价格 黄石新楼盘 黄石深度游 黄石培训班 黄石游玩 黄石做网站 黄石 旅行社 黄石旅游社 黄石二日游