【NOIP2015】【bzoj4326】【uoj146】运输计划 ——O(n*log)算法

来源:互联网 发布:java json格式 编辑:程序博客网 时间:2024/05/21 22:57

最大数据是n,m=300000,所以应该试着把时间压在n*log(xxx)以内 //在本算法下,xxx=n*∑ti

考虑修改一条边后,所有长度大于答案的路径都被缩短,因此二分答案

设二分到的答案为k

那么被删掉的边一定是所有长于k的路径的公共边之一,因此问题转化为,在O(m)时间内求出m条路径的交集中的最长边

首先,可以在O(1)时间内求出两条路径的交集:对于路径s-t 和 s'-t' 分别求出s'到s-t上最近点u,t'到s-t上最近点v,那么交集就是(u,v)

这里若无解,交集会变成s-t上一个点,结束时特判即可。在其他题目中求路径交集需要再反向求一次,在此不详细解释。

求最近点代码如下

int closest(int x,int s,int t){    int r=lca(s,t);    if(lca(x,r)!=r) return r;    int p=lca(x,s);    return p==r?lca(x,t):p;}

大致思路是,若最近点不是s和t 的公共祖先,那么判断是s那侧还是t那侧

其中lca要转化为RMQ,方可O(1)实现

找到交集后,从两个顶点开始逐条边向父节点移动,直到撞上就可以了,效率很低,O(n)但不会影响整体复杂度


代码:

#include<cstdio>#include<algorithm>#include<cstring>#include<vector>using namespace std;#define maxm 300005#define maxn 300005#define maxt 600005#define lca(u,v) rmq(pre[u],pre[v])#define mid (l+r)/2int n,m;struct edge{    int v;    int w;    int next;    edge(int v,int w,int next):v(v),w(w),next(next){}    edge(){}}e[maxn*2];int newedge,dfsclock;int ind[maxn];void addedge(int u,int v,int l){    e[++newedge]=edge(v,l,ind[u]);    ind[u]=newedge;}int f[maxn];int pre[maxn];int dis[maxn],dep[maxn];int visiting[maxt];int st[maxt][20];int log[maxt];void dfs(int u,int fa){    f[u]=fa;    dep[u]=dep[fa]+1;    pre[u]=++dfsclock;    visiting[dfsclock]=u;    for(int i=ind[u];i;i=e[i].next)    {        int v=e[i].v;        if(v!=fa)         {            dis[v]=dis[u]+e[i].w;            dfs(v,u);            visiting[++dfsclock]=u;        }    }}void rmq_init(){    log[1]=0;    for(int i=2;i<=dfsclock;i++) log[i]=log[i>>1]+1;    dep[0]=0x7fffffff;    for(int i=1;i<=dfsclock;i++)        st[i][0]=visiting[i];    for(int l=1,t=0;l<=dfsclock;l<<=1,t++)        for(int i=1;i+l<=dfsclock;i++)            st[i][t+1]=dep[st[i][t]]<dep[st[i+l][t]]?st[i][t]:st[i+l][t];}int rmq(int l,int r){    if(l>r) swap(l,r);    int k=log[r-l+1];    int a=st[l][k],b=st[r-(1<<k)+1][k];    return dep[a]<dep[b]?a:b;}int closest(int x,int s,int t){    int r=lca(s,t);    if(lca(x,r)!=r) return r;    int p=lca(x,s);    return p==r?lca(x,t):p;}struct mission{    int s,t;    int l;    void input()    {        scanf("%d%d",&s,&t);        l=dis[s]+dis[t]-2*dis[lca(s,t)];    }}q[maxm];int ln[maxm];bool operator <(mission a,mission b){    return a.l<b.l;}bool judge(int x){    int p=upper_bound(ln+1,ln+m+1,x)-ln;    if(p==m+1) return true;    int ss=q[p].s,tt=q[p].t;    int maxlen=0;    for(int i=p+1;i<=m;i++)    {        ss=closest(q[i].s,q[i].t,ss);        tt=closest(q[i].s,q[i].t,tt);    }    if(ss==tt) return false;    while(ss!=tt)    {        int &a=dep[ss]>dep[tt]?ss:tt;        maxlen=max(maxlen,dis[a]-dis[f[a]]);        a=f[a];    }    if(ln[m]-maxlen<=x) return true;    else return false;}int main(){    scanf("%d%d",&n,&m);    for(int i=1;i<n;i++)    {        int a,b,t;        scanf("%d%d%d",&a,&b,&t);        addedge(a,b,t);        addedge(b,a,t);    }    dfs(1,0);    rmq_init();    for(int i=1;i<=m;i++) q[i].input();    sort(q+1,q+m+1);    for(int i=1;i<=m;i++) ln[i]=q[i].l;    int l=0,r=0x7fffffff;    while(l<r)    {        if(judge(mid)) r=mid;        else l=mid+1;    }    printf("%d",l);}





0 0
原创粉丝点击