[LOJ6145][2017 山东三轮集训 Day7]Easy

loj

description

一棵树,每次给出\(l,r,x\),求从点\(x\)出发到达\([l,r]\)中任意一点的最短距离。

sol

动态点分治。
建出点分树后,在每个节点上用以点编号为下标的线段树维护出子树中所有点到他的距离。
对于一组询问只要暴跳父亲然后查询就可以了。
一般而言写动态点分治的时候要维护两个东西,一个是当前节点子树的信息,另一个是当前子树给上一级重心(也就是点分树上的父亲的所有贡献)方便在计算时减去。但是在这里,因为题目中要求的是\(min\),而重复计算不会影响结果的正确性(因为距离只可能算大不可能算小),所以只维护一棵线段树就行了。
时间复杂度\(O(n\log^2n)\),注意空间复杂度也是\(O(n\log^2n)\)

code

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int gi(){
    int x=0,w=1;char ch=getchar();
    while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
    if (ch=='-') w=0,ch=getchar();
    while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    return w?x:-x;
}
const int N = 2e5+5;
int n,q,to[N],nxt[N],ww[N],head[N],cnt,dfn[N],tim,dep[N],st[20][N],lg[N];
int sz[N],w[N],sum,root,vis[N],fa[N],rt[N],tot;
struct seg{int ls,rs,mn;}t[N*150];
void link(int u,int v,int w){
    to[++cnt]=v;nxt[cnt]=head[u];ww[cnt]=w;head[u]=cnt;
}
void dfs(int u,int f){
    st[0][dfn[u]=++tim]=dep[u];
    for (int e=head[u];e;e=nxt[e])
        if (to[e]!=f){
            dep[to[e]]=dep[u]+ww[e];dfs(to[e],u);
            st[0][++tim]=dep[u];
        }
}
int dis(int u,int v){
    int res=dep[u]+dep[v];u=dfn[u],v=dfn[v];
    if (u>v) swap(u,v);int k=lg[v-u+1];
    res-=min(st[k][u],st[k][v-(1<<k)+1])<<1;
    return res;
}
void getroot(int u,int f){
    sz[u]=1;w[u]=0;
    for (int e=head[u];e;e=nxt[e])
        if (to[e]!=f&&!vis[to[e]]){
            getroot(to[e],u);
            sz[u]+=sz[to[e]];
            w[u]=max(w[u],sz[to[e]]);
        }
    w[u]=max(w[u],sum-sz[u]);
    if (w[u]<w[root]) root=u;
}
void solve(int u,int f){
    fa[u]=f;vis[u]=1;
    for (int e=head[u];e;e=nxt[e])
        if (!vis[to[e]]){
            sum=sz[to[e]];root=0;
            getroot(to[e],0);solve(root,u);
        }
}
void modify(int &x,int l,int r,int p,int v){
    if (!x) x=++tot,t[x].mn=1e9;t[x].mn=min(t[x].mn,v);
    if (l==r) return;int mid=l+r>>1;
    if (p<=mid) modify(t[x].ls,l,mid,p,v);
    else modify(t[x].rs,mid+1,r,p,v);
}
int query(int x,int l,int r,int ql,int qr){
    if (!x) return (int)1e9;
    if (l>=ql&&r<=qr) return t[x].mn;
    int mid=l+r>>1;
    if (qr<=mid) return query(t[x].ls,l,mid,ql,qr);
    if (ql>mid) return query(t[x].rs,mid+1,r,ql,qr);
    return min(query(t[x].ls,l,mid,ql,qr),query(t[x].rs,mid+1,r,ql,qr));
}
int main(){
    n=gi();
    for (int i=1;i<n;++i){
        int u=gi(),v=gi(),w=gi();
        link(u,v,w);link(v,u,w);
    }
    dfs(1,0);
    for (int i=2;i<=tim;++i) lg[i]=lg[i>>1]+1;
    for (int j=1;j<=lg[tim];++j)
        for (int i=1;i+(1<<j)-1<=tim;++i)
            st[j][i]=min(st[j-1][i],st[j-1][i+(1<<j-1)]);
    w[0]=sum=n;getroot(1,0);solve(root,0);
    for (int i=1;i<=n;++i)
        for (int u=i;u;u=fa[u])
            modify(rt[u],1,n,i,dis(u,i));
    q=gi();while (q--){
        int l=gi(),r=gi(),u=gi(),x=u,ans=1e9;
        while (x) ans=min(ans,query(rt[x],1,n,l,r)+dis(x,u)),x=fa[x];
        printf("%d\n",ans);
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/zhoushuyu/p/9236277.html
今日推荐