zoukankan      html  css  js  c++  java
  • 题解 BZOJ 1912 && luogu P3629 [APIO2010]巡逻 (树的直径)

    本来抄了篇题解,后来觉得题解都太不友好(我太菜了),一气之下自己打。。。一打打到第二天QAQ

    首先什么边也不加时,总路程就是2*(n-1)

    考虑k=1的时候,答案显然是2*(n-1)-直径+1=2*n-直径-1,如果能加一条边的话,因为希望减少的尽可能多,那么只需要把直径的首尾接起来,就不需要来回走,加一就是加了这一条新加入的边。

    而k=2的时候,首先还是往最长链上面思考。然而做k=1的时候已经用掉了一段,我们需要k=2的和k=1的不重叠。

    于是乎,我们跑完直径后之后把直径上的边权全部修改为-1,再跑一遍直径就可以了。那权值为-1的边又被选了就是考虑第一次算这条边的时候加了1,第二次的时候是-1,相当于是这条边没有产生任何贡献。所以最后答案是2(n-1)-(直径1-1)-(直径2-1)=2n-直径1-直径2

    对了,负权的树一定要用DP跑直径,不要像我一样傻乎乎的用dfs(妄想dfs一石二鸟,何不如直接全DP(但我不会用DP记路径))
     
    对比一下大佬的代码:我的需要专门去找第一次直径的路径再修改,就是fd_p()函数,所以会跑得慢一些。。。。

    哪位大佬能教教我DP记路径吗。。。。感激不尽( ⊙ o ⊙ )啊!

    我的傻乎乎的代码

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #define R register int
    using namespace std;
    const int N=100010,Inf=0x3f3f3f3f;
    inline int g() {
        R ret=0,fix=1; register char ch; while(!isdigit(ch=getchar())) fix=ch=='-'?-1:fix;
        do ret=ret*10+(ch^48); while(isdigit(ch=getchar())); return ret*fix;
    }
    int n,k,mx,mx1,cnt,st,ed;
    int pre[N],fir[N],cnte[N],d[N];
    struct edge{
        int v,w,nxt;
        #define v(i) e[i].v
        #define w(i) e[i].w
        #define nxt(i) e[i].nxt
    }e[N<<1];
    inline void add(int u,int v,int w) {v(++cnt)=v,w(cnt)=w,nxt(cnt)=fir[u],fir[u]=cnt;}
    namespace _dp {
        void dp(int u,int fa) {
            for(R i=fir[u];i;i=nxt(i)) {
                R v=v(i);
                if(v==fa) continue;
                dp(v,u);
                mx=max(mx,d[u]+d[v]+w(i));
                d[u]=max(d[u],d[v]+w(i));
            }
        }
        inline void solve() {
            memset(d,0,sizeof(d));
            dp(1,0);
        }
    }
    inline void dfs(int u,int fa) {
        for(R i=fir[u];i;i=nxt(i)) {
            R v=v(i);
            if(v==fa) continue;
            d[v]=d[u]+w(i);
            dfs(v,u);
        }
    }
    inline void solve() {
        memset(d,0x3f,sizeof(d));
        d[1]=0; dfs(1,0); mx=-Inf; st=0,ed=0;
        for(R i=1;i<=n;++i) if(d[i]>mx&&d[i]!=Inf&&i!=1)
            mx=d[i],st=i;
        memset(d,0x3f,sizeof(d));
        d[st]=0,dfs(st,0); mx=-Inf;
        for(R i=1;i<=n;++i) if(d[i]>mx&&d[i]!=Inf&&i!=st) 
            mx=d[i],ed=i;
    }
    inline void fd_p(int u,int fa) {
        for(R i=fir[u];i;i=nxt(i)) {
            R v=v(i);
            if(v==fa) continue;
            fd_p(v,u);
            pre[v]=u; 
            cnte[v]=i;
        }
    }
    signed main() {
        n=g(),k=g();
        for(R i=1,u,v;i<n;++i) u=g(),v=g(),add(u,v,1),add(v,u,1);
        solve();
        if(k==1) {printf("%d
    ",2*n-mx-1); return 0;}
        fd_p(st,0); mx1=mx; pre[st]=0;
        for(R i=ed;i;i=pre[i]) if(cnte[i]&1) w(cnte[i])=-1,w(cnte[i]+1)=-1; else w(cnte[i])=-1,w(cnte[i]-1)=-1;
        mx=0;
        _dp::solve();
        printf("%d
    ",2*n-mx1-mx);
    }

    我看不懂的代码(from ljh2000%%%%%)

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #define R register int 
    using namespace std;
    const int N=100010;
    inline int g() {
        R ret=0,fix=1; register char ch; while(!isdigit(ch=getchar())) fix=ch=='-'?-1:fix;
        do ret=ret*10+(ch^48); while(isdigit(ch=getchar())); return ret*fix;
    }
    int n,k,cnt,anss,ans,rt,S,SP;
    int fir[N],nxt[N],nxte[N],f[N][2];
    struct edge{
        int v,w,nxt;
        #define v(i) e[i].v
        #define w(i) e[i].w
        #define nxt(i) e[i].nxt
    }e[N<<1];
    inline void add(int u,int v,int w) {v(++cnt)=v,w(cnt)=w,nxt(cnt)=fir[u],fir[u]=cnt;}
    inline void dfs(int u,int fa) {
        R crt,s=0,sp=0;
        for(R i=fir[u];i;i=nxt(i)) {
            R v=v(i);
            if(v==fa) continue;
            dfs(v,u);
            crt=f[v][0]+w(i);
            if(crt>f[u][0]) s=nxt[u],sp=nxte[u],f[u][1]=f[u][0],f[u][0]=crt,nxt[u]=v,nxte[u]=i;
            else if(crt>f[u][1]) f[u][1]=crt,s=v,sp=i;
        }
        if(f[u][0]+f[u][1]>ans) {
            ans=f[u][0]+f[u][1]; rt=u,S=s,SP=sp;
        }
    }
    signed main() {
        n=g(),k=g(); R x;
        for(R i=1,u,v;i<n;++i) u=g(),v=g(),add(u,v,1),add(v,u,1);
        dfs(1,0);
        anss=2*(n-1)-ans+1;
        if(k==1) {printf("%d
    ",anss); return 0;}
        if(f[rt][1]>0) {
            x=S; w(SP)=-1; 
            while(nxt[x]) w(nxte[x])=-1,x=nxt[x];
        }
        x=rt;
        while(nxt[x]) w(nxte[x])=-1,x=nxt[x];
        ans=0; memset(f,0,sizeof(f));
        dfs(1,0); anss-=ans-1; printf("%d
    ",anss);
    }

    2019.04.02

  • 相关阅读:
    node.js简单的服务器
    简单的分页1
    定时跳转
    初始化多个vue实例对象
    js获取验证码的方法
    [z]Java代理(jdk静态代理、动态代理和cglib动态代理)
    .net操作word lib DocX
    git常用命令
    [z]查表空间使用情况
    [z]oracle job
  • 原文地址:https://www.cnblogs.com/Jackpei/p/10640217.html
Copyright © 2011-2022 走看看