题目描述
dzy 手上有一张n 个点m 条边的联通无向图,仙人掌是一张每条边最多在一个简单环内的联通无向图。他想求这个无向图的生成仙人掌中最多有多少条边。
但是dzy 觉得这个问题太简单了,于是他定义了“美丽的生成仙人掌”,即在一个生成仙人掌中如果满足对于任意编号为 i,j(i<j) 的两点,存在一条它们之间的简单路径上面有 j−i+1 个点,则这个仙人掌是美丽的。
他现在想要知道这张图的美丽的生成仙人掌中最多有多少条边,你能帮帮他吗?
输入
第一行两个整数n,m。接下来m 行每行两个整数ui,vi,表示这两个点之间有一条无向边。保证图中没有自环。
输出
仅一行一个整数表示答案。
样例输入
2 1
1 2
样例输出
1
提示
【数据规模和约定】
对于10% 的数据,n <=10。
对于30% 的数据,n <=10^3。
对于100% 的数据,n <=10^5,m <= 2n。
第一次接触仙人掌。。。一开始凭借以前的粗略了解,以为是数据结构。。。好吧事实证明我还是too young too simple.
首先,一个没有环的美丽仙人掌肯定是这样的:
1−2−3−4−5−...n (-表示有边相连)
这样才能满足ij间简单路径必须有j-i+1个点的条件。
然后因为每条边只能在一个环内,假设这条链的区间为 [l,r] ,那么仙人掌剩下的边肯定是 [l,r] 间互不交叉的边。(可以画图模拟一下,交叉的话就有两个环了)
这样问题就变成了,给你m条边,使它先形成数条链,然后在各条链中添加最多的互不交叉的边(这显然可以用贪心做)。
但是怎么找链呢?我们可以用并查集把同一条链上的点合并起来。
p[i]表示以i为祖宗的美丽仙人掌贪心时添边的最右端点
s[i]表示以i为祖宗的美丽仙人掌的边数
#include
#include
#include
#include
using namespace std;
int n,m,x,y,u,v,tot,ans;
struct ty
{
int a,b;
}e[200005];
int f[100005],p[100005],s[100005];
int get(int x)
{
if(f[x]==x) return x;else return f[x]=get(f[x]);
}
bool cmp(ty x,ty y)
{
return x.bint main()
{
cin>>n>>m;
for(int i=1;i<=n;i++) f[i]=i;
for(int i=1;i<=m;i++)
{
scanf("%d%d",&x,&y);
if(x>y) swap(x,y);
if(y-x!=1)
{
tot++;
e[tot].a=x;
e[tot].b=y;
}
else
{
u=get(x);
v=get(y);
if(v!=u) //合并左右端点相邻的边
{
f[v]=u;
s[u]=s[u]+s[v]+1;
s[v]=0;
}
}
}
if(tot>0)
{
sort(e+1,e+tot+1,cmp);
x=0;
for(int i=1;i<=tot;i++)
{
u=get(e[i].a);
v=get(e[i].b);
if(u==v&&e[i].a>=p[u]) //该边左右端点必须在同一集合内
{
s[u]++;
p[u]=e[i].b;
}
}
}
for(int i=1;i<=n;i++) ans=max(ans,s[i]);
cout<return 0;
}