bzoj1912: [Apio2010]patrol 巡逻

来源:互联网 发布:怎么查看端口是否打开 编辑:程序博客网 时间:2024/05/03 03:53

传送门
k=0显然每条边都要走两次,答案=(n-1)*2
k=1我们找到树上最长链,在两段连边
在环上的就不用再走一遍了
答案=(n-1)-链长+1
k=2在k=1的基础上将那些边编圈变为-1,再跑最长链
不再环上显然只要一遍
但是在两个环上要走两遍。
答案=(n-1)-链长1+1-链长2+1

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#include<cstdlib>#include<cmath>#define ll long long#define N 100005using namespace std;struct edge{    int from,to,value,next;}e[N*2];int head[N],son1[N],son2[N];int n,k,x,y,u,ans,sum,tot;inline int read(){    int k=0;    char ch=getchar();    for (;ch<'0'||ch>'9';ch=getchar());    for (;ch>='0'&&ch<='9';ch=getchar()) k=k*10+ch-48;    return k;}inline void ins(int x,int y,int u){    e[++tot].from=x;    e[tot].to=y;    e[tot].value=u;    e[tot].next=head[x];    head[x]=tot;}int dfs(int x,int fa){    int ma1=0,ma2=0,now;    for (int i=head[x];i;i=e[i].next)        if (e[i].to!=fa){            now=dfs(e[i].to,x)+e[i].value;            if (now>ma1){                ma2=ma1;                son2[x]=son1[x];                ma1=now;                son1[x]=i;            }             else if (now>ma2){                ma2=now;                son2[x]=i;            }        }    if (ma1+ma2>sum){        sum=ma1+ma2;        u=x;    }    return ma1;}int main(){    n=read();    k=read();    for (int i=1;i<n;i++){        x=read();        y=read();        ins(x,y,1);        ins(y,x,1);    }    ans=(n-1)*2;    sum=u=0;    dfs(1,-1);    ans-=sum-1;    if (k==2){        for (int i=son1[u];i;i=son1[e[i].to]) e[i].value=e[i+1].value=-1;        for (int i=son2[u];i;i=son1[e[i].to]) e[i].value=e[i+1].value=-1;        memset(son1,0,sizeof(son1));        memset(son2,0,sizeof(son2));        sum=u=0;        dfs(1,-1);        ans-=sum-1;     }    printf("%d",ans);}