• [SHOI2008]cactus仙人掌图


    Description
    如果某个无向连通图的任意一条边至多只出现在一条简单回路(simple cycle)里,我们就称这张图为仙人掌图(cactus)。所谓简单回路就是指在图上不重复经过任何一个顶点的回路。

    举例来说,上面的第一个例子是一张仙人图,而第二个不是——注意到它有三条简单回路:(4,3,2,1,6,5,4)、(7,8,9,10,2,3,7)以及(4,3,7,8,9,10,2,1,6,5,4),而(2,3)同时出现在前两个的简单回路里。另外,第三张图也不是仙人图,因为它并不是连通图。显然,仙人图上的每条边,或者是这张仙人图的桥(bridge),或者在且仅在一个简单回路里,两者必居其一。定义在图上两点之间的距离为这两点之间最短路径的距离。定义一个图的直径为这张图相距最远的两个点的距离。现在我们假定仙人图的每条边的权值都是1,你的任务是求出给定的仙人图的直径。

    Input
    输入的第一行包括两个整数n和m(1≤n≤50000以及0≤m≤10000)。其中n代表顶点个数,我们约定图中的顶点将从1到n编号。接下来一共有m行。代表m条路径。每行的开始有一个整数k(2≤k≤1000),代表在这条路径上的顶点个数。接下来是k个1到n之间的整数,分别对应了一个顶点,相邻的顶点表示存在一条连接这两个顶点的边。一条路径上可能通过一个顶点好几次,比如对于第一个样例,第一条路径从3经过8,又从8返回到了3,但是我们保证所有的边都会出现在某条路径上,而且不会重复出现在两条路径上,或者在一条路径上出现两次。

    Output
    只需输出一个数,这个数表示仙人图的直径长度。

    Sample Input 1
    15 3
    9 1 2 3 4 5 6 7 8 3
    7 2 9 10 11 12 13 10
    5 2 14 9 15 10

    Sample Output 1
    8

    Sample Input 2
    10 1
    10 1 2 3 4 5 6 7 8 9 10

    Sample Output 2
    9

    HINT
    对第一个样例的说明:如图,6号点和12号点的最短路径长度为8,所以这张图的直径为8。

    【注意】使用Pascal语言的选手请注意:你的程序在处理大数据的时候可能会出现栈溢出。
    如果需要调整栈空间的大小,可以在程序的开头填加一句:{$M 5000000},其中5000000即
    指代栈空间的大小,请根据自己的程序选择适当的数值。


    首先建立一棵圆方树,记每个环上dfs序最小的点为(x_i),则每个环代表的方点向各自所拥有的(x_i)连一条边权为1的边,环上其他的圆点向方点连一条边权为圆点到所属(x_i)最短距离的边

    然后我们求圆方树的直径,显然是需要记录一条最长链((f[i]))和次长链((g[i]))的。如果当前点是圆点,则直接用(f[i]+g[i])更新答案;如果当前点是方点,则考虑环上所有点(除去每个环内的(x_i),因为在圆方树上(x_i)是方点的父亲),按照一定顺序,用单调队列维护(f[i]+f[j]+dis(i,j))的最大值即可

    单调队列那里显然要破环成链然后倍长……但是我发现我没有倍长也过了……

    /*program from Wolfycz*/
    #include<cmath>
    #include<cstdio>
    #include<vector>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define inf 0x7f7f7f7f
    using namespace std;
    typedef long long ll;
    typedef unsigned int ui;
    typedef unsigned long long ull;
    inline char gc(){
    	static char buf[1000000],*p1=buf,*p2=buf;
    	return p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++;
    }
    inline int frd(){
    	int x=0,f=1; char ch=gc();
    	for (;ch<'0'||ch>'9';ch=gc())	if (ch=='-')	f=-1;
    	for (;ch>='0'&&ch<='9';ch=gc())	x=(x<<3)+(x<<1)+ch-'0';
    	return x*f;
    }
    inline int read(){
    	int x=0,f=1; char ch=getchar();
    	for (;ch<'0'||ch>'9';ch=getchar())	if (ch=='-')	f=-1;
    	for (;ch>='0'&&ch<='9';ch=getchar())	x=(x<<3)+(x<<1)+ch-'0';
    	return x*f;
    }
    inline void print(int x){
    	if (x<0)	putchar('-'),x=-x;
    	if (x>9)	print(x/10);
    	putchar(x%10+'0');
    }
    const int N=1e5,M=2e5;
    int V[N+10],deep[N+10],dfn[N+10],belong[N+10];
    int n,m,Ans,cnt;
    vector<int>vec[N+10];
    int dis(int x,int y,int pos){
    	if (!x||!y)	return 0;
    	if (dfn[x]<dfn[y])	swap(x,y);
    	return min(deep[x]-deep[y],V[pos]-deep[x]+deep[y]);
    }
    struct S1{
    	int pre[(M<<1)+10],now[M+10],child[(M<<1)+10],val[(M<<1)+10],tot;
    	int f[M+10],g[M+10],fa[M+10];
    	void join(int x,int y,int z){pre[++tot]=now[x],now[x]=tot,child[tot]=y,val[tot]=z;}
    	void insert(int x,int y,int z){join(x,y,z),join(y,x,z);}
    	int work(int pos){
    		static int h[(N<<1)+10];
    		int head=1,tail=0,res=0; h[1]=0;//记得清空h[1]
    		for (vector<int>::iterator it=vec[pos].begin();it!=vec[pos].end();it++){
    			if (it==vec[pos].begin())	continue;
    			while (head<=tail&&(dis(h[head],*it,pos)>V[pos]/2||h[head]==*it))	head++;
    			res=max(res,f[*it]+f[h[head]]+dis(h[head],*it,pos));
    			while (head<=tail&&f[h[tail]]<=f[*it])	tail--;
    			h[++tail]=*it;
    		}
    		for (vector<int>::iterator it=vec[pos].begin();it!=vec[pos].end();it++){
    			if (it==vec[pos].begin())	continue;
    			while (head<=tail&&(dis(h[head],*it,pos)>V[pos]/2||h[head]==*it))	head++;
    			res=max(res,f[*it]+f[h[head]]+dis(h[head],*it,pos));
    			while (head<=tail&&f[h[tail]]<=f[*it])	tail--;
    			h[++tail]=*it;
    		}
    		return res;
    	}
    	void dfs(int x){
    		for (int p=now[x],son=child[p];p;p=pre[p],son=child[p]){
    			if (son==fa[x])	continue;
    			fa[son]=x,dfs(son);
    			int V=f[son]+val[p];
    			if (f[x]<V)	g[x]=f[x],f[x]=V;
    			else	if (g[x]<V)	g[x]=V;
    		}
    		if (x<=n)	Ans=max(Ans,f[x]+g[x]);
    		else	Ans=max(Ans,work(x-n));
    	}
    }RST;//Round Square Tree
    struct S2{
    	int pre[(M<<1)+10],now[N+10],child[(M<<1)+10];
    	int fa[N+10],stack[N+10],low[N+10];
    	int Time,tot,top,num;
    	bool instack[N+10];
    	void join(int x,int y){pre[++tot]=now[x],now[x]=tot,child[tot]=y;}
    	void insert(int x,int y){join(x,y),join(y,x);}
    	void dfs(int x){
    		dfn[x]=++Time,deep[x]=deep[fa[x]]+1;
    		for (int p=now[x],son=child[p];p;p=pre[p],son=child[p]){
    			if (son==fa[x])	continue;
    			if (!dfn[son]){
    				fa[son]=x;
    				dfs(son);
    			}else	if (dfn[son]<dfn[x]){
    				V[++cnt]=deep[x]-deep[son]+1;
    				vec[cnt].push_back(son),RST.insert(cnt+n,son,0);
    				for (int i=x;i!=son;i=fa[i])	vec[cnt].push_back(i),RST.insert(cnt+n,i,dis(i,son,cnt));
    			}
    		}
    	}
    	void tarjan(int x){
    		dfn[x]=low[x]=++Time;
    		instack[stack[++top]=x]=1;
    		for (int p=now[x],son=child[p];p;p=pre[p],son=child[p]){
    			if (son==fa[x])	continue;
    			if (!dfn[son])	tarjan(son),low[x]=min(low[x],low[son]);
    			else	if (instack[son])	low[x]=min(low[x],dfn[son]);
    		}
    		if (low[x]==dfn[x]){
    			instack[x]=0,belong[x]=++num;
    			while (stack[top]!=x)	instack[stack[top]]=0,belong[stack[top--]]=num;
    			top--;
    		}
    	}
    	void init(){
    		Time=0;
    		memset(dfn,0,sizeof(dfn));
    	}
    }OT;//Original Tree
    struct S3{
    	int x,y;
    	void insert(int _x,int _y){x=_x,y=_y;}
    }Line[M+10];
    int main(){
    	n=read(),m=read();
    	int L_cnt=0;
    	for (int i=1;i<=m;i++){
    		int k=read(),last=read();
    		for (int j=1;j<k;j++){
    			int x=read();
    			OT.insert(last,x);
    			Line[++L_cnt].insert(last,x);
    			last=x;
    		}
    	}
    	OT.dfs(1),OT.init(),OT.tarjan(1);
    	for (int i=1;i<=L_cnt;i++)
    		if (belong[Line[i].x]!=belong[Line[i].y])
    			RST.insert(Line[i].x,Line[i].y,1);
    	RST.dfs(1);
    	printf("%d
    ",Ans);
    	return 0;
    }
    
  • 相关阅读:
    如何访问到静态的文件,如jpg,js,css?
    内存定位
    虚拟机逃逸
    OpenGL
    测试
    unity3d
    磁力链接
    IDA脚本
    投屏神器
    扫二维码登录
  • 原文地址:https://www.cnblogs.com/Wolfycz/p/10284295.html
Copyright © 2020-2023  润新知