传送门
可以看出在原树上的每一次复制都是一棵完整的子树,用dfs序表示出来就是一段连续的区间。
称原来给的大小为n的树为模板树,最后得到的树为答案树,把一次操作增加的节点看成一块,然后构成的树称为大树。
我们就需要将模板树和答案树结合起来计算答案。
答案树上两点的距离=两点分别走到所在块的根,在大树上走到两个块的lca,撤销进入块lca后两个点共同走过的路径。
第一步的答案就是找到点到它所在块的根在模板树中的距离
第二步,把大树上两点之间的边权定义为答案树上这两个块的根的距离,然后倍增lca求出
第三步,要知道两个点进入lca后具体是走到模板树上的哪个点,分别设为x,y,然后答案减去2*(lca(x,y)在模板树中的深度-lca块的根在模板树中的深度)
求大树中的lca都需要在模板树中找,因为在对应的块里大小关系是一定的,所以可以用主席树求区间k大来搞。
感觉这题的idea非常好,不过数据结构的码力还是太弱了,而且最后被long long的问题搞了好久,果然我还是太弱= =
#include
#include
#include
using namespace std;
#define LL long long
const int N=1e5+5;
const int E=N*2;
const int LOG=20;
int n,m,q,xx,yy,a,nn,size;LL number,b,x,y;
struct hp{LL len;int son1,son2;bool flag;};
struct hq{LL l,r;}interval[N];
LL Link233[N]; int block_root[N];
LL ans;
namespace Model_tree
{
int h[N],father[N],in[N],out[N],val[N],root[N];
int tot,point[N],nxt[E],v[E];
int f[N][LOG+5];
int sum[N*LOG*2],ls[N*LOG*2],rs[N*LOG*2];
inline void addedge(int x,int y)
{
++tot; nxt[tot]=point[x]; point[x]=tot; v[tot]=y;
++tot; nxt[tot]=point[y]; point[y]=tot; v[tot]=x;
}
inline void build_tree(int x,int fa,int dep)
{
h[x]=dep; father[x]=fa; in[x]=++nn; val[nn]=x;
for (int i=1;i<LOG;++i)
f[x][i]=f[f[x][i-1]][i-1];
for (int i=point[x];i;i=nxt[i])
if (v[i]!=fa)
{
f[v[i]][0]=x;
build_tree(v[i],x,dep+1);
}
out[x]=nn;
}
inline int lca(int x,int y)
{
if (h[x]for (int i=LOG-1;i>=0;--i)
if (h[f[x][i]]>=h[y])
x=f[x][i];
if (x==y) return x;
for (int i=LOG;i>=0;--i)
if (f[x][i]!=f[y][i])
x=f[x][i],y=f[y][i];
return f[x][0];
}
inline void build_pretree(int &now,int l,int r,int x)
{
int mid=(l+r)>>1;
sum[++size]=sum[now]+1; ls[size]=ls[now]; rs[size]=rs[now]; now=size;
if (l==r) return;
if (x<=mid) build_pretree(ls[now],l,mid,x);
else build_pretree(rs[now],mid+1,r,x);
}
inline int query_pretree(int lrange,int rrange,int l,int r,int k)
{
int mid=(l+r)>>1;
if (l==r) return l;
int t=sum[ls[rrange]]-sum[ls[lrange]];
if (t>=k) return query_pretree(ls[lrange],ls[rrange],l,mid,k);
else return query_pretree(rs[lrange],rs[rrange],mid+1,r,k-t);
}
}
namespace Big_tree
{
int h[N];
int tot,point[N],nxt[E],v[E],c[E];
int f[N][LOG+5]; LL s[N][LOG+5];
inline void addedge(int x,int y,int z)
{
++tot; nxt[tot]=point[x]; point[x]=tot; v[tot]=y; c[tot]=z;
++tot; nxt[tot]=point[y]; point[y]=tot; v[tot]=x; c[tot]=z;
}
inline void build_lca(int x,int fa,int dep)
{
h[x]=dep;
for (int i=1;i<LOG;++i)
{
f[x][i]=f[f[x][i-1]][i-1];
s[x][i]=s[x][i-1]+s[f[x][i-1]][i-1];
}
for (int i=point[x];i;i=nxt[i])
if (v[i]!=fa)
{
f[v[i]][0]=x;
s[v[i]][0]=(LL)c[i];
build_lca(v[i],x,dep+1);
}
}
inline hp lca(int x,int y)
{
LL sum=0;
hp ans;
if (h[x]for (int i=LOG-1;i>=0;--i)
if (h[f[x][i]]>h[y])
{
sum+=s[x][i];
x=f[x][i];
}
if (f[x][0]==y)
{
sum+=s[x][0];
return ans=(hp){sum,x,x,true};
}
if (h[x]!=h[y]) sum+=s[x][0],x=f[x][0];
for (int i=LOG-1;i>=0;--i)
if (f[x][i]!=f[y][i])
{
sum+=s[x][i]+s[y][i];
x=f[x][i],y=f[y][i];
}
sum+=s[x][0]+s[y][0];
return ans=(hp){sum,x,y,false};
}
}
inline int find(int l,int r,LL x)
{
int mid;
while (l<=r)
{
mid=(l+r)>>1;
if (x>=interval[mid].l&&x<=interval[mid].r) return mid;
if (xmid].l) r=mid-1;
else l=mid+1;
}
return mid;
}
inline int calc_len(int l,int r,LL x)
{
int int_x=find(l,r,x);
int rank_x=(int)(x-interval[int_x].l+1);
int x_in_model=Model_tree::query_pretree(Model_tree::root[ Model_tree::in[ block_root[int_x] ]-1 ],Model_tree::root[ Model_tree::out[ block_root[int_x] ] ],1,n,rank_x);
int ans=Model_tree::h[x_in_model]-Model_tree::h[block_root[int_x]];
return ans;
}
int main()
{
scanf("%d%d%d",&n,&m,&q);
for (int i=1;i"%d%d",&xx,&yy);
Model_tree::addedge(xx,yy);
}
Model_tree::build_tree(1,0,1);
for (int i=1;i<=n;++i)
{
Model_tree::root[i]=Model_tree::root[i-1];
Model_tree::build_pretree(Model_tree::root[i],1,n,Model_tree::val[i]);
}
interval[1].l=1; interval[1].r=(LL)n; block_root[1]=1;
number=(LL)n;
for (int i=1;i<=m;++i)
{
scanf("%d%lld",&a,&b);
int int_size=Model_tree::out[a]-Model_tree::in[a]+1;
interval[i+1].l=number+1; interval[i+1].r=number+(LL)int_size;
number+=(LL)int_size;
int int_b=find(1,i+1,b);
Link233[i+1]=b; block_root[i+1]=a;
int len=calc_len(1,i+1,b)+1;
Big_tree::addedge(int_b,i+1,len);
}
Big_tree::build_lca(1,0,1);
for (int i=1;i<=q;++i)
{
scanf("%lld%lld",&x,&y);
int int_x=find(1,m+1,x),int_y=find(1,m+1,y);
if (Big_tree::h[int_x]1,m+1,x)+(LL)calc_len(1,m+1,y);
LL aa,bb;
if (int_x!=int_y)
{
hp r=Big_tree::lca(int_x,int_y);
ans+=r.len;
if (r.flag)
{
aa=Link233[r.son1];
bb=y;
}
else
{
aa=Link233[r.son1];
bb=Link233[r.son2];
}
}
else aa=x,bb=y;
int inter=find(1,m+1,aa);
int rank_a=(int)(aa-interval[inter].l+1);
int rank_b=(int)(bb-interval[inter].l+1);
int a_in_model=Model_tree::query_pretree(Model_tree::root[ Model_tree::in[ block_root[inter] ]-1 ],Model_tree::root[ Model_tree::out[ block_root[inter] ] ],1,n,rank_a);
int b_in_model=Model_tree::query_pretree(Model_tree::root[ Model_tree::in[ block_root[inter] ]-1 ],Model_tree::root[ Model_tree::out[ block_root[inter] ] ],1,n,rank_b);
int LCA=Model_tree::lca(a_in_model,b_in_model);
ans-=(LL)(2*(Model_tree::h[LCA]-Model_tree::h[block_root[inter]]));
printf("%lld\n",ans);
}
}