zoukankan      html  css  js  c++  java
  • [IOI2008]Island

    题目链接:Click here

    Solution:

    一句话题意:给定基环树森林,求每颗基环树的直径之和

    考虑基环树求直径的方法,考虑基环树套路,把环和树分开考虑

    我们先把环找出来,对环上的点的子树求直径,再求出这个点开始的最长链,这个很简单,可以用treedp做

    考虑一颗基环树的直径可能有哪些情况:基环树上某棵子树的直径或是一棵子树走到另一颗子树

    第一种情在我们dp的时候就处理完了,考虑第二种情况怎么做

    从一颗子树走到另一颗子树肯定是要经过环上的点的,所以第二种情况必然是一种这样的形式(f[x]+f[y]+dis(x,y))

    其中(f[x])表示以(x)为起点,终点在其子树内的最长链的长度,在dp中已经处理好了,(dis(x,y))表示环上两点(x,y)的距离

    我们把环拆成链来考虑,再把这条链倍长,这样它就能描述任意(dis(x,y))

    我们考虑记(dis[x])表示(x)到链上第一个点的距离,那么(dis(x,y)=dis[x]-dis[y])(这里我们钦定(x)(y)之后)则直径可被表述为(f[x]+f[y]+dis[x]-dis[y])

    倘若我们直接对于环上每个点枚举另外一个点来算直径,时间复杂度是(O(n^2))的,考虑如何来优化

    考虑把上面的式子转化形式:(f[x]+dis[x]+f[y]-dis[y]),我们确定了(x),则(f[y]-dis[y])越大越好,那么就很显然的单调队列优化,我们用单调队列来维护(f[x]-dis[x])的值即可,时间复杂度(O(n))

    找环可以用拓扑排序,然后本题需要开long long

    Code:

    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    const int N=2e6+11;
    int n,cnt,head[N],d[N];
    int tot,ring[N],vis[N],id[N];
    int hd,tl,v[N],son[N];
    ll edis,ans,dis[N],f[N],g[N];
    queue<int> q;
    struct Edge{int nxt,to,val;}edge[N<<1];
    void ins(int x,int y,int z){
        edge[++cnt].nxt=head[x];
        edge[cnt].to=y;head[x]=cnt;
        edge[cnt].val=z;
    }
    void dfs(int x){
        ring[++tot]=x;vis[x]=1;id[x]=tot;
        for(int i=head[x];i;i=edge[i].nxt){
            int y=edge[i].to;
            if(id[y]==1&&id[x]==tot) edis=edge[i].val;
            if(vis[y]) continue;
            dis[tot+1]=edge[i].val;dfs(y);
        }
    }
    void treedp1(int x,int fa){
        for(int i=head[x];i;i=edge[i].nxt){
            int y=edge[i].to;
            if(id[y]||y==fa) continue;
            int w=edge[i].val;
            treedp1(y,x);
            if(f[x]<f[y]+w){
                g[x]=f[x];f[x]=f[y]+w;
                son[x]=y;
            }else if(g[x]<f[y]+w) g[x]=f[y]+w;
        }
    }
    void treedp2(int x,int fa,ll &Mx){
        if(f[x]+g[x]>Mx) Mx=f[x]+g[x];
        for(int i=head[x];i;i=edge[i].nxt){
            int y=edge[i].to;
            if(id[y]||y==fa) continue;
            int w=f[x]+edge[i].val;
            if(y==son[x]) w=g[x]+edge[i].val;
            if(f[y]<w){g[y]=f[y];f[y]=w;son[y]=x;}
            else if(g[y]<w) g[y]=w;
            treedp2(y,x,Mx);
        }
    }
    void work(){
        ll re=0,mxdis=0;hd=1,tl=0;
        for(int i=1;i<=tot;i++){
            treedp1(ring[i],0);
            treedp2(ring[i],0,mxdis);
        }int limit=tot;
        ring[++tot]=ring[1];
        dis[tot]=edis;
        for(int i=2;i<=limit;i++){
            ring[++tot]=ring[i];
            dis[tot]=dis[tot-limit];
        }
        for(int i=2;i<=tot;i++) dis[i]+=dis[i-1];
        for(int i=1;i<=tot;i++){
            int x=ring[i];
            while(hd<=tl&&i-v[hd]>=limit) ++hd;
            if(hd<=tl) re=max(re,f[ring[v[hd]]]-dis[v[hd]]+f[x]+dis[i]);
            while(tl>=hd&&f[ring[v[tl]]]-dis[v[tl]]<f[x]-dis[i]) --tl;v[++tl]=i;
        }re=max(re,mxdis);ans+=re;
    }
    void topsort(){
        for(int i=1;i<=n;i++)
            if(d[i]==1) q.push(i),vis[i]=1;
        while(!q.empty()){
            int x=q.front();q.pop();
            for(int i=head[x];i;i=edge[i].nxt){
                int y=edge[i].to;
                if(vis[y]) continue;
                --d[y];if(d[y]==1) vis[y]=1,q.push(y);
            }
        }
        for(int i=1;i<=n;i++){
            if(vis[i]) continue;
            tot=0;dfs(i);work();
        }
    }
    int read(){
    	int x=0,f=1;char ch=getchar();
    	while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();}
    	while(isdigit(ch)){x=x*10+ch-48;ch=getchar();}
    	return x*f;
    }
    signed main(){
        n=read();
        for(int i=1;i<=n;i++){
            int x=read(),z=read();
            ins(i,x,z),ins(x,i,z);++d[x],++d[i];
        }topsort();printf("%lld
    ",ans);
        return 0;
    }
    
  • 相关阅读:
    Java学习笔记-函数
    Java学习笔记-数组
    Git 常用命令速查表
    $.fn与$.fx什么意思; $.extend与$.fn.extend用法区别; $(function(){})和(function(){})(jQuery)
    offsetWidth的bug
    jQuery对象和DOM对象转换,解决jQuery对象不能使用js方法的问题
    1
    $().ready()与window.onload的不同
    offsetHeight在不同的浏览器下取值不同
    getElementsByName兼容ie 但并不是兼容ie下的所有标签
  • 原文地址:https://www.cnblogs.com/NLDQY/p/11734499.html
Copyright © 2011-2022 走看看