[2017集训队作业自选题#117]Monkey and Tree

来源:互联网 发布:cnc编程兼职群 编辑:程序博客网 时间:2024/06/06 07:18

题目大意

一颗边权树,给你若干点对(ai,bi)。
找到两对点对i和j,使得dis(ai,aj)+dis(bi,bj)最大。

做法

先建立点分树。
然后进行点分,对于当前分治中心x,讨论最终点对中两个a路径是否过x。
不过x,递归处理。
过x,求出当前分治联通块每个点到x的距离,然后接下来按一个一个子树处理(一起询问,再一起插入,来保证不在同一个子树),我们把b插入到点分树中,对于点分树一个分治中心y,处理出dis(a,x)+dis(b,y)的最大值、最大值来自哪个子树以及不来自同一个子树的次大值,即可完成询问。

#include<cstdio>#include<algorithm>#define fo(i,a,b) for(i=a;i<=b;i++)using namespace std;typedef long long ll;const int maxn=100000+10;const ll inf=10000000000000000;int h[maxn],go[maxn*2],dis[maxn*2],nxt[maxn*2],a[maxn];int ask[maxn][2],h2[maxn],g2[maxn],n2[maxn],size[maxn];int belong[maxn][25],son[maxn][25],mxf[maxn];int sta[maxn];ll d[maxn],dep[maxn][25],mx[maxn],se[maxn];bool bz[maxn],pd[maxn];int i,j,k,l,t,n,m,top,tot,cnt;ll ans;int read(){    int x=0,f=1;    char ch=getchar();    while (ch<'0'||ch>'9'){        if (ch=='-') f=-1;        ch=getchar();    }    while (ch>='0'&&ch<='9'){        x=x*10+ch-'0';        ch=getchar();    }    return x*f;}void add(int x,int y,int z){    go[++tot]=y;    dis[tot]=z;    nxt[tot]=h[x];    h[x]=tot;}void add2(int x,int y){    g2[++tot]=y;    n2[tot]=h2[x];    h2[x]=tot;}void travel(int x,int y){    a[++top]=x;    size[x]=1;    int t=h[x];    while (t){        if (!bz[go[t]]&&go[t]!=y){            travel(go[t],x);            size[x]+=size[go[t]];        }        t=nxt[t];    }}void dg(int x,int y,int d,int c){    son[x][d]=c;    int t=h[x];    while (t){        if (!bz[go[t]]&&go[t]!=y){            dep[go[t]][d]=dep[x][d]+(ll)dis[t];            dg(go[t],x,d,c);        }        t=nxt[t];    }}void build(int x,int y){    top=0;    travel(x,0);    int i,t,j=x,k=0;    while (1){        t=h[j];        while (t){            if (!bz[go[t]]&&go[t]!=k&&size[go[t]]>top/2){                k=j;                j=go[t];                break;            }            t=nxt[t];        }        if (!t) break;    }    fo(i,1,top) belong[a[i]][y]=j;    t=h[j];    while (t){        if (!bz[go[t]]){            dep[go[t]][y]=dis[t];            dg(go[t],j,y,go[t]);        }        t=nxt[t];    }    son[j][y]=j;    bz[j]=1;    t=h[j];    while (t){        if (!bz[go[t]]) build(go[t],y+1);        t=nxt[t];    }}void change(int x,ll v){    int j;    int y;    ll w;    fo(j,0,25){        y=belong[x][j];        if (!pd[y]){            pd[y]=1;            sta[++cnt]=y;        }        w=v+dep[x][j];        if (mxf[y]==son[x][j]) mx[y]=max(mx[y],w);        else if (w>=mx[y]){            se[y]=mx[y];            mx[y]=w;            mxf[y]=son[x][j];        }        else if (w>=se[y]) se[y]=w;        if (x==y) break;    }}void query(int x,ll v){    int j;    int y;    ll w;    fo(j,0,25){        y=belong[x][j];        if (mx[y]==-inf) return;        w=v+dep[x][j];        if (mxf[y]==son[x][j]) ans=max(ans,w+se[y]);        else ans=max(ans,w+mx[y]);        if (x==y) break;    }}void cx(int x,int y,int d){    int t=h2[x];    while (t){        query(g2[t],dep[x][d]);        t=n2[t];    }    t=h[x];    while (t){        if (!bz[go[t]]&&go[t]!=y) cx(go[t],x,d);        t=nxt[t];    }}void cr(int x,int y,int d){    int t=h2[x];    while (t){        change(g2[t],dep[x][d]);        t=n2[t];    }    t=h[x];    while (t){        if (!bz[go[t]]&&go[t]!=y) cr(go[t],x,d);        t=nxt[t];    }}void solve(int x,int y){    int j=belong[x][y];    cnt=0;    int t=h2[j];    while (t){        query(g2[t],0);        change(g2[t],0);        t=n2[t];    }    t=h[j];    while (t){        if (!bz[go[t]]){            cx(go[t],j,y);            cr(go[t],j,y);        }        t=nxt[t];    }    int i;    fo(i,1,cnt){        pd[sta[i]]=0;        mx[sta[i]]=se[sta[i]]=-inf;        mxf[sta[i]]=0;    }    bz[j]=1;    t=h[j];    while (t){        if (!bz[go[t]]) solve(go[t],y+1);        t=nxt[t];    }}int main(){    n=read();m=read();    fo(i,1,n-1){        j=read();k=read();l=read();        add(j,k,l);add(k,j,l);    }    tot=0;    fo(i,1,m){        ask[i][0]=read();ask[i][1]=read();        add2(ask[i][0],ask[i][1]);    }    build(1,0);    fo(i,1,n) mx[i]=se[i]=-inf;    fo(i,1,n) bz[i]=0;    solve(1,0);    printf("%lld\n",ans);}
原创粉丝点击