• [bzoj1791][ioi2008]Island 岛屿(基环树、树的直径)


    [bzoj1791][ioi2008]Island 岛屿(基环树、树的直径)

    bzoj luogu

    题意可能会很绕

    一句话:基环树的直径。

    求直径:

    对于环上每一个点记录其向它的子树最长路径为$dp_x$

    之后记录环上边长前缀和$ns_i$

    dp值为$max_{i,j}dp[i]+sum[i]+dp[j]-sum[j]$

    $dp[j]-sum[j]$提出来进单调队列。

    O(n)。

    记得dfs改bfs。

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    typedef long long lint;
    const int N=1145141;
    template<typename TP>inline void read(TP &kk){
        TP ret=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){ret=ret*10+ch-'0';ch=getchar();}
        kk=ret*f;
    }
    int n;
    struct sumireko{int to,ne,w;}e[N*2];
    int he[N],ecnt;
    void addline(int f,int t,int w)
    {
        e[++ecnt].to=t;
        e[ecnt].w=w;
        e[ecnt].ne=he[f];
        he[f]=ecnt;
    }
    bool vv[N],onr[N];
    int rnd[N*2],hp,sp,nw[N*2];
    lint ns[N*2];
    
    int find(int x,int f)
    {
        if(vv[x]){sp=x;return 1;}
        vv[x]=1;int tmp;
        for(int i=he[x],t;i;i=e[i].ne)
        {
            t=e[i].to;
            if(i==((f&1)?f+1:f-1)) continue;
            if(tmp=find(t,i))
            {
                if(tmp==1)
                {
                    rnd[++hp]=x;
                    onr[x]=1;
                    nw[hp]=e[i].w;
                    if(x!=sp) return 1;
                }
                return 2;
            }
        }
        return 0;
    }
    lint dp[N],ans0,ans1;
    int h,l;
    int st[N];
    bool use[N];
    int fa[N];
    void bfs(int u)
    {
        h = 1,l = 0;
        st[++l] = u;
        use[u]=1;
        while(h<=l)
        {
            u = st[h++];
            for(int j=he[u];j;j=e[j].ne)
            {
                int to = e[j].to;
                if(use[to]||onr[to])continue;
                use[to] = 1;
                fa[to] = u;
                st[++l] = to;
            }
        }
        for(int i=l;i>=1;i--)
        {
            u = st[i];
            for(int j=he[u];j;j=e[j].ne)
            {
                int to = e[j].to;
                if(onr[to]||to==fa[u])continue;
                lint tmp = dp[to]+e[j].w;
                ans0 = max(ans0,dp[u]+tmp);
                dp[u]=max(dp[u],tmp);
            }
        }
    }
    lint ans;
    int qu[N*2],qh,qt;
    void fuck(int xx)
    {
        ans0=ans1=0;
        hp=0;
        find(xx,0);
        int x;
        for(int i=1;i<=hp;i++)
        {
            x=rnd[i];
            bfs(x);
            nw[i+hp]=nw[i];
            rnd[i+hp]=rnd[i];
        }
        for(int i=1;i<=2*hp;i++) ns[i]=ns[i-1]+nw[i];
        qh=1,qt=0;
        for(int i=1;i<2*hp;i++)
        {
            while(qh<qt&&qu[qh]+hp<=i) qh++;
            if(qh<=qt)ans1=max(ans1,dp[rnd[i]]+ns[i]+dp[rnd[qu[qh]]]-ns[qu[qh]]);
            while(qh<=qt&&dp[rnd[qu[qt]]]-ns[qu[qt]]<=dp[rnd[i]]-ns[i]) qt--;
            qu[++qt]=i;
        }    
        ans+=max(ans0,ans1);
        hp=0;
    }
    
    int xi,yi,wi;
    signed main()
    {
        read(n);
        for(int i=1;i<=n;i++)
        {
            read(xi),read(wi);
            addline(i,xi,wi),addline(xi,i,wi);
        }
        for(int i=1;i<=n;i++) if(!use[i]) fuck(i);
        printf("%lld
    ",ans);
        return 0;
    }
    View Code
  • 相关阅读:
    Cocos2d-x之CCMenu理解
    【问题记录】mysql设置任意ip访问
    kafka eagle 使用教程
    查看Android源码和源码布局
    JAVA问题之泛型数组
    Linux面试题汇总答案(转)
    从源码看Azkaban作业流下发过程
    Azkaban源码学习笔记
    Java多线程基础学习(二)
    Java多线程基础学习(一)
  • 原文地址:https://www.cnblogs.com/rikurika/p/11290067.html
Copyright © 2020-2023  润新知