BZOJ4539 : [Hnoi2016]树

用主席树维护DFS序来支持询问某个点的子树中第$k$小的编号。

然后建出模板树和缩块之后的树。

如果两个点在同一个树块内,那么答案就是它们在模板树上的距离。

否则先在缩块后的树上求出块顶之间的距离,然后加上内部距离。

时间复杂度$O(n\log n)$。

 

#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=100010,M=N*18;
int n,m,q,cnt,i,x,y;
int g[N],v[N<<1],nxt[N<<1],ed;
int f[N],d[N],size[N],son[N],top[N],st[N],en[N],dfn,seq[N];
int tot,T[N],l[M],r[M],val[M];
struct P{int s;ll e;P(){}P(int _s,ll _e){s=_s,e=_e;}}a[N];
inline void read(int&a){char c;while(!(((c=getchar())>='0')&&(c<='9')));a=c-'0';while(((c=getchar())>='0')&&(c<='9'))(a*=10)+=c-'0';}
inline void read(ll&a){char c;while(!(((c=getchar())>='0')&&(c<='9')));a=c-'0';while(((c=getchar())>='0')&&(c<='9'))(a*=10)+=c-'0';}
inline void add(int x,int y){v[++ed]=y;nxt[ed]=g[x];g[x]=ed;}
void dfs(int x){
  size[x]=1;
  for(int i=g[x];i;i=nxt[i])if(v[i]!=f[x]){
    f[v[i]]=x,d[v[i]]=d[x]+1;
    dfs(v[i]),size[x]+=size[v[i]];
    if(size[v[i]]>size[son[x]])son[x]=v[i];
  }
}
void dfs2(int x,int y){
  seq[st[x]=++dfn]=x,top[x]=y;
  if(son[x])dfs2(son[x],y);
  for(int i=g[x];i;i=nxt[i])if(v[i]!=son[x]&&v[i]!=f[x])dfs2(v[i],v[i]);
  en[x]=dfn;
}
inline int lca(int x,int y){
  for(;top[x]!=top[y];x=f[top[x]])if(d[top[x]]<d[top[y]])swap(x,y);
  return d[x]<d[y]?x:y;
}
int ins(int x,int a,int b,int c){
  int y=++tot;val[y]=val[x]+1;
  if(a==b)return y;
  int mid=(a+b)>>1;
  if(c<=mid)l[y]=ins(l[x],a,mid,c),r[y]=r[x];else l[y]=l[x],r[y]=ins(r[x],mid+1,b,c);
  return y;
}
inline int kth(int x,int k){
  int a=1,b=n,mid,t,A=T[en[x]],B=T[st[x]-1];
  while(a<b){
    mid=(a+b)>>1;
    t=val[l[A]]-val[l[B]];
    if(k<=t)A=l[A],B=l[B],b=mid;else k-=t,A=r[A],B=r[B],a=mid+1;
  }
  return a;
}
inline int block(ll x){
  int l=1,r=cnt,mid,t;
  while(l<=r)if(a[mid=(l+r)>>1].e>=x)r=(t=mid)-1;else l=mid+1;
  return t;
}
namespace BIG{
int ed,g[N],v[N],w[N],fn[N],f[N],d[N],size[N],son[N],top[N];ll dis[N];
inline void add(int x,int y,int A,int B){fn[y]=A;v[++ed]=y;w[ed]=B;nxt[ed]=g[x];g[x]=ed;}
void dfs(int x){
  size[x]=1;
  for(int i=g[x];i;i=nxt[i]){
    f[v[i]]=x,d[v[i]]=d[x]+1,dis[v[i]]=dis[x]+w[i];
    dfs(v[i]),size[x]+=size[v[i]];
    if(size[v[i]]>size[son[x]])son[x]=v[i];
  }
}
void dfs2(int x,int y){
  top[x]=y;
  if(son[x])dfs2(son[x],y);
  for(int i=g[x];i;i=nxt[i])if(v[i]!=son[x])dfs2(v[i],v[i]);
}
inline int lca(int x,int y){
  for(;top[x]!=top[y];x=f[top[x]])if(d[top[x]]<d[top[y]])swap(x,y);
  return d[x]<d[y]?x:y;
}
inline int lca2(int x,int y){
  int t;
  while(top[x]!=top[y])t=top[y],y=f[top[y]];
  return x==y?t:son[x];
}
}
inline int dist(int x,int y){return d[x]+d[y]-2*d[lca(x,y)];}
inline ll query(ll x,ll y){
  int Ax=block(x),Bx=kth(a[Ax].s,x-a[Ax-1].e),
      Ay=block(y),By=kth(a[Ay].s,y-a[Ay-1].e);
  if(Ax==Ay)return dist(Bx,By);
  ll t;int z=BIG::lca(Ax,Ay);
  if(z!=Ax&&z!=Ay){
    t=d[Bx]-d[a[Ax].s]+d[By]-d[a[Ay].s];
    int Cx=BIG::lca2(z,Ax),Cy=BIG::lca2(z,Ay);
    t+=BIG::dis[Ax]-BIG::dis[Cx]+BIG::dis[Ay]-BIG::dis[Cy]+2;
    t+=dist(BIG::fn[Cx],BIG::fn[Cy]);
  }else if(z==Ax){
    t=d[By]-d[a[Ay].s];
    int Cy=BIG::lca2(z,Ay);
    t+=BIG::dis[Ay]-BIG::dis[Cy]+1;
    t+=dist(Bx,BIG::fn[Cy]);
  }else{
    t=d[Bx]-d[a[Ax].s];
    int Cx=BIG::lca2(z,Ax);
    t+=BIG::dis[Ax]-BIG::dis[Cx]+1;
    t+=dist(By,BIG::fn[Cx]);
  }
  return t;
}
int main(){
  read(n),read(m),read(q);
  for(i=1;i<n;i++)read(x),read(y),add(x,y),add(y,x);
  dfs(1),dfs2(1,1);
  for(i=1;i<=n;i++)T[i]=ins(T[i-1],1,n,seq[i]);
  a[++cnt]=P(1,n);
  for(i=2;i<=m+1;i++){
    int x,A,B;ll y;
    read(x),read(y);
    A=block(y),B=kth(a[A].s,y-a[A-1].e);
    a[i]=P(x,a[i-1].e+size[x]);
    cnt++;
    BIG::add(A,i,B,d[B]-d[a[A].s]+1);
  }
  BIG::dfs(1);
  BIG::dfs2(1,1);
  while(q--){
    ll x,y;
    read(x),read(y);
    printf("%lld\n",query(x,y));
  }
  return 0;
}

  

posted @ 2016-04-19 17:09  Claris  阅读(676)  评论(0编辑  收藏  举报