您的位置:首页 > 其它

JZOJ3845. 【NOIP2014八校联考第1场第1试9.20】简单题(simple)

2018-02-08 11:54 489 查看

Description

dzy 手上有一张n 个点m 条边的联通无向图,仙人掌是一张每条边最多在一个简单环内的联通无向图。他想求这个无向图的生成仙人掌中最多有多少条边。

但是dzy 觉得这个问题太简单了,于是他定义了“美丽的生成仙人掌”,即在一个生成仙人掌中如果满足对于任意编号为i,j(i < j) 的两点,存在一条它们之间的简单路径上面有j-i+1 个点,则这个仙人掌是美丽的。

他现在想要知道这张图的美丽的生成仙人掌中最多有多少条边,你能帮帮他吗?

Input

第一行两个整数n,m。接下来m 行每行两个整数ui,vi,表示这两个点之间有一条无向边。保证图中没有自环。

Output

仅一行一个整数表示答案。

Sample Input

2 1

1 2

Sample Output

1

Data Constraint

对于10% 的数据,n <=10。

对于30% 的数据,n <=10^3。

对于100% 的数据,n <=10^5,m <= 2n。

题解

先考虑如何满足对于任意编号为i,j(i < j) 的两点,存在一条它们之间的简单路径上面有j-i+1 个点这个要求。

很显然唯一能满足的就是一条链,且链上面点的编号都是连续的。

现在就要构造边数最多的仙人掌了。

两个环是不能相交的,但可以相切。

问题就转化成了线段覆盖问题,

在一条连续的链[l,r]中,

有一些线段xi,yi,l≤xi<yi≤r

要求线段不能重复覆盖,是的选取的线段尽可能多。

一个简单的dp就可以了,

是fi表示前面i个位置都已经处理完了(不一定都不线段覆盖)的最多边数。

code

#include<queue>
#include<cstdio>
#include<iostream>
#include<algorithm>
#include <cstring>
#include <string.h>
#include <cmath>
#include <math.h>
#include <time.h>
#define ll long long
#define N 100003
#define M 103
#define db double
#define P putchar
#define G getchar
#define inf 998244353
using namespace std;
char ch;
void read(int &n)
{
n=0;
ch=G();
while((ch<'0' || ch>'9') && ch!='-')ch=G();
ll w=1;
if(ch=='-')w=-1,ch=G();
while('0'<=ch && ch<='9')n=(n<<3)+(n<<1)+ch-'0',ch=G();
n*=w;
}

int max(int a,int b){return a>b?a:b;}
int min(int a,int b){return a<b?a:b;}
ll abs(ll x){return x<0?-x:x;}
ll sqr(ll x){return x*x;}
void write(ll x){if(x>9) write(x/10);P(x%10+'0');}

int nxt[N<<2],to[N<<2],lst
,tot;
int n,m,x,y,cnt,l,r,f
,ans;
bool p
;
struct node
{
int x,y;
}a[N<<2];
bool cmp(node a,node b)
{
return a.x<b.x || (a.x==b.x  && a.y<b.y);
}

void ins(int x,int y)
{
nxt[++tot]=lst[x];
to[tot]=y;
lst[x]=tot;
}

int main()
{
read(n);read(m);
for(int i=1;i<=m;i++)
{
read(x),read(y),ins(x,y),ins(y,x);
if(x>y)swap(x,y);
if(x+1==y)p[x]=1;
}

for(l=1;r<=n;l=r+1)
{
cnt=0;
for(r=l;p[r];r++);
for(int i=l;i<=r;i++)
for(int j=lst[i];j;j=nxt[j])
if(l<=to[j] && to[j]<=r && abs(to[j]-i)>1)a[++cnt].x=i,a[cnt].y=to[j];
sort(a+1,a+1+cnt,cmp);
f[a[0].x=l]=0;
for(int i=1;i<=cnt;i++)
{
for(int j=a[i-1].x+1;j<=a[i].x;j++)
f[j]=max(f[j],f[j-1]);
f[a[i].y]=f[a[i].x]+1;
}
for(int i=a[cnt].x+1;i<=r;i++)
f[i]=max(f[i],f[i-1]);
ans=max(ans,f[r]+r-l+1);
}

write(ans);

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐