[NOIP 2005] 运输计划

link

这是一道假的图论

思维难度很低,代码量偏高

就是一道板子+二分

树上差分就AC了

注意卡常即可

二分枚举答案x,为时间长度

将每一个长度大于x的计划链长记录下来(有几个,总需要减少多少长度)

在树上跑一跑即可

树上差分就将u,vv权值+1,lca(u,v)-2即可

dp[i]:为子树权值和,也是i上面道路有几条路径覆盖

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
inline int read()
{
    int f=1,ans=0;char c;
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();}
    return f*ans;
}
int n,m;
struct node{
    int u,v,w,nex;
}x[600001];
int deep[300001],vt[300001],dis[300001],fa[300001][21],head[300001],cnt=1;
void add(int u,int v,int w)
{
    x[cnt].u=u,x[cnt].v=v,x[cnt].w=w,x[cnt].nex=head[u],head[u]=cnt++;
}
void dfs(int f,int fath,int DIS)
{
    deep[f]=deep[fath]+1;
    dis[f]=DIS;
    fa[f][0]=fath;
    for(int i=1;(1<<i)<=deep[f];i++) fa[f][i]=fa[fa[f][i-1]][i-1];
    for(int i=head[f];i;i=x[i].nex)
    {
        if(x[i].v==fath) continue;
        vt[x[i].v]=x[i].w;
        dfs(x[i].v,f,DIS+x[i].w);
    }
    return;
}
int lca(int u,int v)
{
    if(deep[u]<deep[v]) swap(u,v);
    for(int i=19;i>=0;i--) 
        if(deep[u]-(1<<i)>=deep[v]) u=fa[u][i];
    if(u==v) return u;
    for(int i=19;i>=0;i--)
    {
        if(fa[u][i]==fa[v][i]) continue;
        u=fa[u][i],v=fa[v][i];
    }return fa[u][0];
}
struct node1{
    int x,y,lca,dis;
}s[300001];
int l,r,mid,dp[300001];
void dp_tree(int f,int fath)
{
    for(int i=head[f];i;i=x[i].nex)
    {
        if(x[i].v==fath) continue;
        dp_tree(x[i].v,f);
        dp[f]+=dp[x[i].v];
    }
    return;
}
bool check(int st)
{
    memset(dp,0,sizeof(dp));
    int tot=0,maxn=0;
    for(int i=1;i<=m;i++)
    {
        if(s[i].dis>st)
        {
            tot++;
            dp[s[i].x]++,dp[s[i].y]++,dp[s[i].lca]-=2;
            maxn=max(maxn,s[i].dis-st);
        }
    }
    dp_tree(1,0);
    for(int i=2;i<=n;i++) 
        if(dp[i]==tot&&vt[i]>=maxn) return 1;
    return 0;
}
int data=2<<30-1;
int main()
{
    n=read(),m=read();
    for(int i=1;i<n;i++)
    {
        int u=read(),v=read(),w=read();
        add(u,v,w),add(v,u,w);
    }
    dfs(1,0,0);
    for(int i=1;i<=m;i++)
    {
        s[i].x=read(),s[i].y=read();
        s[i].lca=lca(s[i].x,s[i].y);
        s[i].dis=dis[s[i].x]+dis[s[i].y]-(dis[s[i].lca]<<1);
        r=max(r,s[i].dis);
    }
    while(l<=r)
    {
        mid=l+r>>1;
        if(check(mid)) data=min(data,mid),r=mid-1;
        else l=mid+1;
    }
    printf("%d",data);
}
View Code

 

posted @ 2018-09-28 19:57  siruiyang_sry  阅读(175)  评论(0编辑  收藏  举报