您的位置:首页 > 其它

仙人掌直径

2016-07-20 19:04 190 查看
Bzoj1023

大概终于是把这个老坑填上了、以后碰到基环树和仙人掌直径都用这个方法做了,反正也不算长。

首先我们讨论一下仙人掌里面的边(为什么不先讨论点呢。因为点会被多个环公用你说不清楚)

而边就要简单很多只分为割边和非割边(也可以叫环边)而环又都是简单环,考虑一次dfs

在讨论完边的基础上哪些点是关键点呢,当然和割边有关,首先是一条割边先遍历到的那个点,这个点和生成树的根性质很相似所以显然会有用,然后是一条割边后遍历的那个点(当然也可能包括dfs开始的起始点)这个点被作为每个环的最高点,形象一点理解的话就是dfs这个环的起始点。

我们先思考那些根节点需要怎么操作,这个还是比较容易的        ans=max(ans,f[x]+f[y]+1);

                                          f[x]=max(f[x],f[y]+1);f[x]为以这个点向下遍历的最大深度

然后是那些最高点,最高点要复杂一些我们可以先找到一个简单环的头和尾,然后破环成链

然后用一个单调队列维护(维护的是始末点都在环上的答案)

最后随便乱搞一下得到f【x】就好了。。。

#include <cstdio> 

#include <cmath> 

#include <ctime> 

#include <string> 

#include <cstring> 

#include <cstdlib> 

#include <iostream> 

#include <algorithm> 

 

#include <set>

#include <stack> 

#include <queue> 

#include <vector> 

#include<map>

#include<list>

 

#define pb push_back

#define lb lower_bound

#define sqr(x) (x)*(x)

#define lowbit(x) (x)&(-x) 

#define Abs(x) ((x) > 0 ? (x) :(-(x))) 

#define forup(i,a,b) for(inti=(a);i<=(b);i++) 

#define fordown(i,a,b) for(inti=(a);i>=(b);i--) 

#define ls(a,b) (((a)+(b)) << 1) 

#define rs(a,b) (((a)+(b)) >> 1) 

#define getlc(a) ch[(a)][0] 

#define getrc(a) ch[(a)][1] 

 

#define maxn 400005

#define maxm 100005

#define INF 1070000000 

using namespace std; 

typedef long long ll; 

typedef unsigned long long ull; 

 

template<class T> inline 

void read(T& num){ 

   num = 0; bool f = true;char ch = getchar(); 

   while(ch < '0' || ch > '9') { if(ch == '-') f = false;ch =getchar();} 

   while(ch >= '0' && ch <= '9') {num = num * 10 + ch -'0';ch = getchar();} 

   num = f ? num: -num; 

}

int out[100];

template<class T> inline

void write(T x,char ch){

 if(x==0) {putchar('0'); putchar(ch); return;}

 if(x<0) {putchar('-'); x=-x;}

 intnum=0;

 while (x){ out[num++]=(x%10); x=x/10;}

 fordown(i,num-1,0) putchar(out[i]+'0'); putchar(ch);

}

/*==================splitline==================*/

vector<int> g[maxn];

intque[maxn],dfn[maxn],fa[maxn],a[maxn],f[maxn];//fx为不包括自己的向下最大深度

int ans=0;

int Clock=0;

int n,m;

void dp(int x,int y)

{ int cnt=0;

   while(x!=y)

        {a[++cnt]=f[y];

          y=fa[y];

         }

         a[++cnt]=f[x];

          for(int i=1;i<cnt;i++)//破环成链

          {a[cnt+i]=a[i];  }

          int l=1,r=1;

          int p=cnt/2;

          que[1]=1;

          forup(i,2,cnt+p)

          { while(l<=r&&i-que[l]>p) l++;

          ans=max(ans,a[que[l]]+a[i]+i-que[l]);

            while(l<=r&&a[que[r]]+i-que[r]<=a[i])

             r--;

             que[++r]=i;

          }

          for(int i=1;i<cnt;i++)

          f[x]=max(f[x],a[i]+min(i,cnt-i));

}

 

int tarjan(int x)

{   intlowx=dfn[x]=++Clock;

   for(int i=0;i<g[x].size();i++)

    {int v=g[x][i];

      if(v!=fa[x])

       {    if(!dfn[v])

              { fa[v]=x;

                int lowv=tarjan(v);

                 lowx=min(lowx,lowv);

                 if(dfn[x]<lowv)//割边

                                    { ans=max(ans,f[x]+f[v]+1);

                                       f[x]=max(f[x],f[v]+1);

                                    }

                           }

                         else  lowx=min(lowx,dfn[v]);

            }

        }

        for(inti=0;i<g[x].size();i++)

         { int v=g[x][i];

            if(x!=fa[v]&&dfn[x]<dfn[v])//找到环的最高点

                    dp(x,v);

         }

         return lowx;

}

int main()

{ read(n);read(m);

 

        forup(i,1,m)

        {intk,x,y;

                 read(k);read(x);

                 for(int j=1;j<k;j++)

                 {read(y);

                         g[x].pb(y);g[y].pb(x);

                         x=y;

                 }

        }

        tarjan(1);

        write(ans,'\n');

       

       

        return0;
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: