【HNOI2015】开店

来源:互联网 发布:移动硬盘mac不显示 编辑:程序博客网 时间:2024/03/29 18:29

题目大意

给出一棵有n个节点的树,每条边有个边长,每个节点有个权值a[i],有q个询问形如”u l r”询问点u到所有权值在l到r之间的点的路径长度和

一眼解法

一个点与多个点之间的距离和,显然我们可以用点分治来做,对于每个分治中心,我们将其所有该层的点都记录下来,那么每层共有n个,最多nlog2n个,同时,在我们计算答案时要计算每个分治中心对其父亲的影响。
询问时我们就直接在重心树上跳,沿途记录答案就好了。

贴代码:

#include<cstring>#include<cstdio>#include<algorithm>#include<cmath>#include<iostream>#define fo(i,a,b) for(int i=a;i<=b;i++)#define fd(i,a,b) for(int i=a;i>=b;i--)using namespace std;typedef long long LL;typedef double db;const int N = 150010;int n,Q,A;int v[N];int fa[N],q[N],m,s[N],vis[N],tim,mv[N];bool bz[N];int f[N];struct point{    int x,v;    LL s;}a[N*20];int r[N],k,l[N];int ce[N],rt[N*2],u,rmq[N*2][20],fir[N];LL dis[N];int h[N],tot;struct edge{    int x,len,next;}e[N*2];int get(){    char ch;    int s=0;    while(ch=getchar(),ch<'0'||ch>'9');    s=ch-'0';    while(ch=getchar(),ch>='0'&&ch<='9')s=s*10+ch-'0';    return s;}void inse(int x,int y,int z){    e[++tot].x=y;    e[tot].len=z;    e[tot].next=h[x];    h[x]=tot;}void dfs(int x){    rt[fir[x]=++u]=x;    for(int p=h[x];p;p=e[p].next)        if (!fir[e[p].x]){            ce[e[p].x]=ce[x]+1;            dis[e[p].x]=dis[x]+e[p].len;            dfs(e[p].x);            rt[++u]=x;        }}void getrmq(){    fo(i,1,u)rmq[i][0]=rt[i];    fo(j,1,log(u)/log(2))        fo(i,1,u-(1<<j)+1)        if (ce[rmq[i][j-1]]<ce[rmq[i+(1<<(j-1))][j-1]])rmq[i][j]=rmq[i][j-1];        else rmq[i][j]=rmq[i+(1<<(j-1))][j-1];}LL getdis(int x,int y){    if (!x||!y)return 0;    LL ans=dis[x]+dis[y];    x=fir[x],y=fir[y];    if (x>y)swap(x,y);    int t=log(y-x+1)/log(2);    if (ce[rmq[x][t]]<ce[rmq[y-(1<<t)+1][t]])return ans-2*dis[rmq[x][t]];    return ans-2*dis[rmq[y-(1<<t)+1][t]];}bool cmp(point x,point y){    return x.v<y.v;}void bfs(int x){    vis[q[m=1]=x]=++tim;    s[x]=1;    mv[x]=0;    int head=0;    while(head<m){        x=q[++head];        for(int p=h[x];p;p=e[p].next)            if (!bz[e[p].x]&&vis[e[p].x]<tim){                vis[q[++m]=e[p].x]=tim;                fa[e[p].x]=x;                s[e[p].x]=1;                mv[e[p].x]=0;            }    }}int solve(int x,int last){    bfs(x);    int w=0;    fd(i,m,1){        x=q[i];        s[fa[x]]+=s[x];        mv[fa[x]]=max(mv[fa[x]],s[x]);        mv[x]=max(mv[x],m-s[x]);        if (mv[x]*2<=m)w=x;    }    bz[w]=1;    l[w]=k;    r[w]=k+m;    fo(i,1,m){        a[++k].x=q[i];        a[k].v=v[q[i]];    }    sort(a+l[w]+1,a+r[w]+1,cmp);    fo(i,l[w]+1,l[w]+m){        x=a[i].x;        if (last)a[i].s=getdis(last,x);        a[i].s=getdis(w,x)-a[i].s;        if (i>l[w]+1)a[i].s=a[i].s+a[i-1].s;    }    for(int p=h[w];p;p=e[p].next)        if (!bz[e[p].x])f[solve(e[p].x,w)]=w;    return w;}int getw(int d,int u,int v){    int w=u+1,l=d,r=u;    while(l<=r){        int mid=(l+r)/2;        if (a[mid].v<v)l=mid+1;        else{            r=mid-1;            w=mid;        }    }    return w;}LL getans(int L,int R,int u){    int x=u,ls=0;    LL ans=0;    while(x){        int w1=getw(l[x]+1,r[x],L),w2=getw(l[x]+1,r[x],R+1)-1;        LL v=a[w1-1].s;        if (w1==l[x]+1)v=0;        if (w2>=w1)ans+=a[w2].s-v+LL(w2-w1+1-ls)*getdis(x,u);        ls=max(0,w2-w1+1);        x=f[x];    }    return ans;}int main(){    freopen("shop.in","r",stdin);    freopen("shop.out","w",stdout);    n=get(),Q=get(),A=get();    fo(i,1,n)v[i]=get();    fo(i,1,n-1){        int x=get(),y=get(),z=get();        inse(x,y,z);        inse(y,x,z);    }    dfs(ce[1]=1);    getrmq();    solve(1,0);    LL ans=0;    fo(i,1,Q){            int u=get();            int a=get(),b=get();            int L=min((a+ans)%A,(b+ans)%A),R=max((a+ans)%A,(b+ans)%A);            printf("%lld\n",ans=getans(L,R,u));    }    fclose(stdin);    fclose(stdout);    return 0;}
0 0