bzoj1023: [SHOI2008]cactus仙人掌图

仙人掌。

仙人掌入门题。。不过入门都好难。。。

题解好复杂。。

总体来说,没有环的话,就是一棵树,很好求。

如果有环的话,就找出这个环,用一个单调队列用环上俩个点对更新答案。(如果不用单调队列就O(n^2)超时)

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn = 3000000 + 10;

int g[maxn],v[maxn],next[maxn],eid;
int p[maxn],w[maxn],dis[maxn];
int low[maxn],dfn[maxn],fa[maxn];
int ring[maxn],cnt;
int n,m,res;

void addedge(int a,int b) {
    v[eid]=b; next[eid]=g[a]; g[a]=eid++;
    v[eid]=a; next[eid]=g[b]; g[b]=eid++;    
}

void getring() {
    int l=1,r=1;
    for(int i=1;i<=cnt;i++) ring[i+cnt]=ring[i];
    for(int i=1;i<=(cnt<<1);i++) {
        while(l<r && i-p[l]>(cnt>>1)) l++;
        while(l<r && w[r]<=dis[ring[i]]-i) r--;
        ++r;
        p[r]=i;
        w[r]=dis[ring[i]]-i;
        res=max(res,dis[ring[i]]+i+w[l]);    
    }
}
    
void dfs(int u) {
    low[u]=dfn[u];
    for(int i=g[u];~i;i=next[i]) 
        if(fa[v[i]] && v[i] !=fa[u]) 
            low[u]=min(low[u],dfn[v[i]]);
        else if(!fa[v[i]]) {
            fa[v[i]]=u;
            dfn[v[i]]=dfn[u]+1;
            dfs(v[i]);
            low[u]=min(low[u],low[v[i]]);
        }
        
    for(int i=g[u];~i;i=next[i]) {
        if(fa[v[i]]==u && low[v[i]]>dfn[u]) {
            res=max(res,dis[v[i]]+1+dis[u]);    
            dis[u]=max(dis[u],dis[v[i]]+1);
        }
        if(fa[v[i]]!=u && dfn[u]<dfn[v[i]]) {
            int p=v[i]; cnt=0;
            while(p!=fa[u]) {
                ring[++cnt]=p;
                p=fa[p];
            }
            getring();
            for(int j=1;j<cnt;j++) 
                dis[u]=max(dis[u],dis[ring[j]]+min(j,cnt-j));
        }
    }
}

int main() {
    memset(g,-1,sizeof(g));
    scanf("%d%d",&n,&m);
    for(int i=1,a,b,x;i<=m;i++) {
        scanf("%d%d",&x,&a);
        for(int j=2;j<=x;j++) {
            scanf("%d",&b);
            addedge(a,b);
            a=b;
        }
    }
    fa[1]=-1;
    dfs(1);
    printf("%d\n",res);
    return 0;
}

posted @ 2016-07-01 18:18  invoid  阅读(182)  评论(0编辑  收藏  举报