BZOJ 2282: [Sdoi2011]消防

来源:互联网 发布:优化客户对策 编辑:程序博客网 时间:2024/04/27 13:45

这题其实跟之前那个什么破清北学堂第一周D2T2差不多
不过当然多了点东西

做法

这条路径显然是在直径上的 这个yy一下就好
然后求出直径后直接在直径上移一下取min就好了

有人打二分? 不懂(而且讲道理复杂度会变大吧?
当然是打个单调队列啦(这种挪来挪去的东西

代码

看到一个人的代码写的实在好看和简洁
于是很愉快地 借鉴了一下他的代码 (我的代码绝对可以说比他的好看
速度也挺可观的

#include<bits/stdc++.h>using namespace std;const int N=3e5+2,inf=1e9+7;char B[1<<14],*S=B,*T=B;#define gc (S==T&&(T=(S=B)+fread(B,1,1<<14,stdin),S==T)?-1:*S++)inline int read(){    int x=0,f=1; char ch=gc;    while(ch<'0' || ch>'9'){if(ch=='-')f=-1; ch=gc;}    while(ch>='0' && ch<='9'){x=(x<<1)+(x<<3)+ch-'0'; ch=gc;}    return x*f;}struct node{int y,c,nex;}a[N<<1]; int len,fir[N];void ins(int x,int y,int c){    a[++len]=(node){y,c,fir[x]},fir[x]=len;}int n,m,f[N],fa[N],g[N],v[N];int h[N],p[N],o[N],z[N],he,ta;queue<int>q;inline int bfs(int x,int t){    int i,len=0;    q.push(x); g[x]=0,fa[x]=x,v[x]=t;    while(!q.empty()){        x=q.front(); q.pop();        for(int k=fir[x];k;k=a[k].nex){            int y=a[k].y;  if(v[y]==t)continue;            g[y]=g[x]+a[k].c;            fa[y]=x,v[y]=t,q.push(y);            len=max(len,g[y]);        }    }    return len;}int main(){    n=read(),m=read(); int i,s,t;    for(i=1;i<n;++i){        int x=read(),y=read(),c=read();        ins(x,y,c),ins(y,x,c);    }    int ti=0;    for(s=1,bfs(s,++ti),i=2;i<=n;++i) if(g[i]>g[s])s=i;    for(t=1,bfs(s,++ti),i=2;i<=n;++i) if(g[i]>g[t])t=i;    p[n=1]=t,++ti;    do{ t=fa[t],p[++n]=t,v[t]=ti; }while(t!=s);    for(i=1;i<=n;++i)f[i]=g[p[1]]-g[p[i]];    for(i=1;i<=n;++i)o[i]=g[p[i]];    for(i=1;i<=n;++i)h[i]=bfs(p[i],ti);    for(i=1;i<=n;++i)g[i]=o[i];    int l,r=0,ans=inf; he=1,ta=0;    for(l=1;l<=n;++l){        while(r<n && f[r+1]-f[l]<=m){            ++r;            while(he<=ta && h[z[ta]]<=h[r]) ta--;            z[++ta]=r;        }        ans=min(ans,max(max(f[l],g[r]),h[z[he]]));        if(z[he]<=l)he++;    }    printf("%d\n",ans);    return 0;}
原创粉丝点击