仙人掌直径
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;
大概终于是把这个老坑填上了、以后碰到基环树和仙人掌直径都用这个方法做了,反正也不算长。
首先我们讨论一下仙人掌里面的边(为什么不先讨论点呢。因为点会被多个环公用你说不清楚)
而边就要简单很多只分为割边和非割边(也可以叫环边)而环又都是简单环,考虑一次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;
相关文章推荐
- 杭电-2012 素数判定 (素数打表)
- 【幻化万千戏红尘】qianfengDay03-java基础学习:for循环,switch,if
- 线程同步
- 练习笔记
- Agri-Net
- Python-S13作业-day4-之登陆,管理后台
- 【幻化万千戏红尘】qianfengDay02-java基础学习:运算符、进制转换
- 大数 加法 c语言
- 一个Sqrt函数引发的血案
- [leetcode] 169. Majority Element
- 【幻化万千戏红尘】qianfengDay01-java基础学习:历史、数据类型
- HBase集群管理
- Codeforces 154C Double Profiles
- 编译Memcached测试客户端连接【web级ubuntu速学课程】
- NYOJ 1112 求次数 (map)
- 函数指针的运用于程序示例
- 大数据学习-hadoop -第三课附加- hadoop RPC源码分析
- HDU 2080 夹角有多大II(余弦公式)
- Yarn中几个专用名称
- Qt qml listview刷新