zoukankan      html  css  js  c++  java
  • 【Luogu】P3761城市(dfs)

      题目链接

      emmm我思维好水……

      想了一会lct发现好像不对,然后开始转DP稍微有一点思路,然后看了题解……

      首先可以枚举边,然后原树被你拆成了两个子树。

      设D1D2是两个子树的直径,W1W2是子树内某个点到其他点最长距离的最小值,val是断掉的边的权值

      然后呢我们发现此时的答案成为了max(max(D1,D2),W1+W2+val)

      然后可以发现W1W2可以通过枚举子树直径上的点求得。

      然后这样就TLE了23333

      一个大优化是我们可以发现枚举断掉哪条边这个步骤可以变成枚举断掉直径上哪条边,只有这样才能对答案产生影响

      然后就快了九倍……

      

    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<algorithm>
    #include<cctype>
    #define maxn 6000
    using namespace std;
    inline long long read(){
        long long num=0,f=1;
        char ch=getchar();
        while(!isdigit(ch)){
            if(ch=='-')    f=-1;
            ch=getchar();
        }
        while(isdigit(ch)){
            num=num*10+ch-'0';
            ch=getchar();
        }
        return num*f;
    }
    
    int n;
    
    struct Edge{
        int next,to,val;
    }edge[maxn*2];
    int head[maxn],num;
    inline void add(int from,int to,int val){
        edge[++num]=(Edge){head[from],to,val};
        head[from]=num;
    }
    
    int dis[maxn];
    bool vis[maxn];
    
    void find(int x,int fa,int lim){
        for(int i=head[x];i;i=edge[i].next){
            int to=edge[i].to;
            if(to==fa||to==lim)    continue;
            dis[to]=dis[x]+edge[i].val;
            find(to,x,lim);
        }
        return;
    }
    
    void record(int x,int fa,int goal){
        if(x==goal){
            vis[x]=1;
            return;
        }
        for(int i=head[x];i;i=edge[i].next){
            int to=edge[i].to;
            if(to==fa)    continue;
            record(to,x,goal);
            if(vis[to])    vis[x]=1;
        }
        return;
    }
    
    struct ANSWER{
        int x,y;
    };
    
    ANSWER ask(int x,int fa){
        memset(vis,0,sizeof(vis));
        memset(dis,-1,sizeof(dis));
        dis[x]=0;
        find(x,fa,fa);
        int now=0;
        for(int i=1;i<=n;++i)
            if(dis[i]>dis[now])    now=i;
        dis[now]=0;
        find(now,now,fa);
        int to=0;
        for(int i=1;i<=n;++i)
            if(dis[i]>dis[to])    to=i;
        record(now,now,to);
        ANSWER ans=(ANSWER){dis[to],0x7fffffff};
        for(int i=1;i<=n;++i)
            if(vis[i])    ans.y=min(ans.y,max(dis[to]-dis[i],dis[i]));
        return ans;
    }
    
    bool vie[maxn*3];
    
    int main(){
        n=read();
        for(int i=1;i<n;++i){
            int from=read(),to=read(),val=read();
            add(from,to,val);
            add(to,from,val);
        }
        ask(1,0);
        for(int i=1;i<=num;i+=2){
            if(vis[edge[i].to]==0||vis[edge[i+1].to]==0)    continue;
            vie[i]=1;
        }
        int ans=0x7fffffff;
        for(int i=1;i<=num;i+=2){
            if(vie[i]==0)    continue;
            int from=edge[i].to,to=edge[i+1].to,val=edge[i].val;
            ANSWER l1=ask(from,to);    ANSWER l2=ask(to,from);
        //    printf("%d %d %d %d %d %d %d
    ",from,to,val,l1.x,l1.y,l2.x,l2.y);
            ans=min(ans,max(max(l1.x,l2.x),l1.y+l2.y+val));
        }
        printf("%d
    ",ans);
        return 0;
    }
  • 相关阅读:
    [置顶] 某大型银行深化系统技术方案之一:实现技术定义
    android代码实现关机
    一个IP每天只弹一次广告窗口
    bootstrap框架开发电子商城案例
    HDU 1203 I NEED A OFFER!(dp)
    STL algorithmi算法s_sorted和is_sorted_until(28)
    计数排序(C语言版本)
    4.事务提交过程,交易的基本概念,Oracle交易周期,保存点savepoint,数据库的隔离级别
    《python源代码分析》笔记 pythonVM一般表达式
    ASP.NET——两个下拉框来实现动态联动
  • 原文地址:https://www.cnblogs.com/cellular-automaton/p/8818161.html
Copyright © 2011-2022 走看看