zoukankan      html  css  js  c++  java
  • 仙人掌图直径

    题:https://www.luogu.com.cn/problem/P4244

    分析:定义f[i]表示dfs过程中 i 节点到子树叶子节点的最大距离;

       考虑俩种边的俩种情况,【1】假设枚举边为树边(桥),那么对答案的更新则为f[u]+f[v]+1,表示在枚举v之前的最大叶子节点距离和当前v节点到叶子节点的最大距离,同时用f[v]更新f[u].

                  【2】考虑环,环对答案的更新无非就选取俩个点i,j 的f[i]+f[j]+abs(i-j)。那么对于当前的i,只要找到最大的f[j]-j ,所以维护这样一个环的单调队列。

    #include<bits/stdc++.h>
    using namespace std;
    #define pb push_back
    #define ull unsigned long long
    #define pii pair<int,int>
    #define MP make_pair
    typedef long long ll;
    const ll INF=1e18;
    const int M=5e5+6;
    int deep[M],a[M],fa[M],f[M],que[M],low[M],dfn[M];
    vector<int>g[M];
    int ans,cnt;
    void solve(int u,int v){
        int sum=deep[v]-deep[u]+1;
        for(int i=v;i!=u;i=fa[i])
            a[sum--]=f[i];
        a[1]=f[u];
        sum=deep[v]-deep[u]+1;
        que[1]=1;
        int head=1,tail=1;
        for(int i=1;i<=sum;i++)
            a[i+sum]=a[i];
        for(int i=2;i<=sum+(sum>>1);i++){
            if(i-que[head]>(sum>>1))head++;///因为俩点间的距离是最短距离,所以把选的范围缩小为环的一半,这也是为什么要枚举3/2环
            ans=max(ans,a[i]+a[que[head]]+i-que[head]);///对于更新答案,a[i]+i是确定的,那么只要找到最大的a[j]-j即可,也就是维护a[j]-j的单调队列,保证头部是最大的
            while(head<=tail&&a[i]-i>=a[que[tail]]-que[tail])
                tail--;
            que[++tail]=i;
        }
        for(int i=2;i<=sum;i++)
            f[u]=max(f[u],a[i]+min(i-1,sum-i+1));///因为定义俩点最短距离为2,所以选取环的较短边。
    }
    void dfs(int u){
        dfn[u]=low[u]=++cnt;
        for(auto v:g[u]){
            if(v!=fa[u]){
                if(!dfn[v]){
                    deep[v]=deep[u]+1;
                    fa[v]=u;
                    dfs(v);
                }
                low[u]=min(low[u],low[v]);
                if(low[v]>dfn[u]){
                    ans=max(ans,f[u]+f[v]+1);
                    f[u]=max(f[u],f[v]+1);
                }
            }
        }
        for(auto v:g[u]){
            if(fa[v]!=u&&dfn[v]>dfn[u])
                solve(u,v);
        }
    }
    int main(){
        int n,m;
        scanf("%d%d",&n,&m);
        while(m--){
            int k,u=0,v;
            scanf("%d",&k);
            while(k--){
                scanf("%d",&v);
                if(u)g[u].pb(v),g[v].pb(u);
                u=v;
            }
        }
        dfs(1);
        printf("%d
    ",ans);
        return 0;
    }
    View Code
  • 相关阅读:
    prototype.js超强的javascript类库
    MySQL Server Architecture
    Know more about RBA redo block address
    MySQL无处不在
    利用Oracle Enterprise Manager Cloud Control 12c创建DataGuard Standby
    LAMP Stack
    9i中DG remote archive可能导致Primary Database挂起
    Oracle数据库升级与补丁
    Oracle为何会发生归档日志archivelog大小远小于联机重做日志online redo log size的情况?
    Oracle Ksplice如何工作?How does Ksplice work?
  • 原文地址:https://www.cnblogs.com/starve/p/13533369.html
Copyright © 2011-2022 走看看