2282: [Sdoi2011]消防 树的直径+二分答案

来源:互联网 发布:dns设置软件 编辑:程序博客网 时间:2024/06/10 03:53

显然这条路径在树的直径上,随便YY一下就知道了这个。
开始写的DFS据说会爆栈= =于是改成了BFS。
然后我们求出直径,就可以二分答案,双指针向里缩,最后看两个指针之间距离是否合法。

#include<iostream>#include<cstdio>#include<cstring>#define N 300005using namespace std;int n,s,cnt,top,S,T;int dis[N],q[N],stack[N],head[N],from[N];bool mark[N];int next[N<<1],list[N<<1],key[N<<1];inline int read(){    int a=0,f=1; char c=getchar();    while (c<'0'||c>'9') {if (c=='-') f=-1; c=getchar();}    while (c>='0'&&c<='9') {a=a*10+c-'0'; c=getchar();}    return a*f;}inline void insert(int x,int y,int z){    next[++cnt]=head[x];    head[x]=cnt;    list[cnt]=y;    key[cnt]=z;}inline void bfs(int st){    memset(dis,-1,sizeof(dis));    int t=0,w=1;    q[1]=st; dis[st]=0;    while (t<w)    {        int x=q[++t];        for (int i=head[x];i;i=next[i])            if (dis[list[i]]==-1)            {                from[list[i]]=x;                dis[list[i]]=dis[x]+key[i];                q[++w]=list[i];            }    }}inline void find_path(){    int x=T;    stack[++top]=dis[x]; mark[x]=1;    while (x!=S) stack[++top]=dis[from[x]],x=from[x],mark[x]=1;}inline void calc_dis(int st){    memset(dis,-1,sizeof(dis));    int t=0,w=1;    q[1]=st; dis[st]=0;    while (t<w)    {        int x=q[++t];        for (int i=head[x];i;i=next[i])            if (dis[list[i]]==-1)            {                if (mark[list[i]]) dis[list[i]]=dis[x];                else dis[list[i]]=dis[x]+key[i];                q[++w]=list[i];            }    }}inline bool judge(int mid){    int l=1,r=top;    while (stack[1]-stack[l+1]<=mid&&l<=top) l++;    while (stack[r-1]<=mid&&r) r--;    return stack[l]-stack[r]<=s;}int main(){    n=read(); s=read();    for (int i=1;i<n;i++)    {        int u=read(),v=read(),w=read();        insert(u,v,w); insert(v,u,w);    }    bfs(1);    for (int i=1;i<=n;i++) if (dis[i]>dis[S]) S=i;    bfs(S);    for (int i=1;i<=n;i++) if (dis[i]>dis[T]) T=i;    int l=0,r=dis[T];    find_path();    calc_dis(S);      for (int i=1;i<=n;i++) l=max(l,dis[i]);    while (l<=r)    {        int mid=l+r>>1;        if (judge(mid)) r=mid-1; else l=mid+1;    }    cout << l << endl;    return 0;}
0 0
原创粉丝点击