BZOJ4539

来源:互联网 发布:泛突厥主义知乎 编辑:程序博客网 时间:2024/05/22 08:17

4539: [Hnoi2016]树

Time Limit: 40 Sec  Memory Limit: 256 MB
Submit: 510  Solved: 194
[Submit][Status][Discuss]

Description

  小A想做一棵很大的树,但是他手上的材料有限,只好用点小技巧了。开始,小A只有一棵结点数为N的树,结
点的编号为1,2,…,N,其中结点1为根;我们称这颗树为模板树。小A决定通过这棵模板树来构建一颗大树。构建过
程如下:(1)将模板树复制为初始的大树。(2)以下(2.1)(2.2)(2.3)步循环执行M次(2.1)选择两个数字a,b,
其中1<=a<=N,1<=b<=当前大树的结点数。(2.2)将模板树中以结点a为根的子树复制一遍,挂到大树中结点b的下
方(也就是说,模板树中的结点a为根的子树复制到大树中后,将成为大树中结点b的子树)。(2.3)将新加入大树
的结点按照在模板树中编号的顺序重新编号。例如,假设在进行2.2步之前大树有L个结点,模板树中以a为根的子
树共有C个结点,那么新加入模板树的C个结点在大树中的编号将是L+1,L+2,…,L+C;大树中这C个结点编号的大小
顺序和模板树中对应的C个结点的大小顺序是一致的。下面给出一个实例。假设模板树如下图:


根据第(1)步,初始的大树与模板树是相同的。在(2.1)步,假设选择了a=4,b=3。运行(2.2)和(2.3)后,得到新的
大树如下图所示

现在他想问你,树中一些结点对的距离是多少。

Input

  第一行三个整数:N,M,Q,以空格隔开,N表示模板树结点数,M表示第(2)中的循环操作的次数,Q 表示询问数
量。接下来N-1行,每行两个整数 fr,to,表示模板树中的一条树边。再接下来M行,每行两个整数x,to,表示将模
板树中 x 为根的子树复制到大树中成为结点to的子树的一次操作。再接下来Q行,每行两个整数fr,to,表示询问
大树中结点 fr和 to之间的距离是多少。N,M,Q<=100000

Output

  输出Q行,每行一个整数,第 i行是第 i个询问的答案。

Sample Input

5 2 3
1 4
1 3
4 2
4 5
4 3
3 2
6 9
1 8
5 3

Sample Output

6
3
3

HINT

经过两次操作后,大树变成了下图所示的形状:



结点6到9之间经过了6条边,所以距离为6;类似地,结点1到8之间经过了3条边;结点5到3之间也经过了3条边。

Source

对于这个题,我不想发表什么意见了

注意longlong,切记,注意longlong!!!


#include<cstdio>#include<cstdlib>#include<cstring>#include<algorithm>#define maxn 100005using namespace std;typedef long long ll;struct node{int lc,rc,cnt;}seg[maxn*20];struct kuai{ll l,r;int rt;kuai(){}kuai(ll l,ll r,int rt):l(l),r(r),rt(rt){}int operator<(const kuai& k)const{return r<k.r;}}op[maxn];struct edge{int r,nxt;}e[maxn<<1],xe[maxn<<1];struct data{int conn,ra;data(){}data(int conn,int ra):conn(conn),ra(ra){}};int fa[maxn][20],ptr,head[maxn],root[maxn],esz,dep[maxn],dfn[maxn],tot,size[maxn],top,tim[maxn],n,m,q;ll xdist[maxn][20],dist[maxn],now;data xfa[maxn][20];void modify(int rt1,int &rt2,int l,int r,int k){rt2=++ptr;seg[rt2]=seg[rt1];seg[rt2].cnt++;if(l==r)return ;int mid=l+r>>1;if(k<=mid)modify(seg[rt1].lc,seg[rt2].lc,l,mid,k);else modify(seg[rt1].rc,seg[rt2].rc,mid+1,r,k);}int query(int rt1,int rt2,int l,int r,int k){if(l==r)return l;int sz=seg[seg[rt2].lc].cnt-seg[seg[rt1].lc].cnt;int mid=l+r>>1;if(sz>=k)return query(seg[rt1].lc,seg[rt2].lc,l,mid,k);else return query(seg[rt1].rc,seg[rt2].rc,mid+1,r,k-sz);}int dfs(int u,int f,int d){fa[u][0]=f,dist[u]=d;dfn[++top]=u,tim[u]=top,size[u]=1;for(int i=1;i<20;++i)fa[u][i]=fa[fa[u][i-1]][i-1];for(int t=head[u];t;t=e[t].nxt)if(e[t].r!=f)size[u]+=dfs(e[t].r,u,d+1);return size[u];}int getid(int rt,int k){return query(root[tim[rt]-1],root[tim[rt]+size[rt]-1],1,n,k);}int getkuai(ll u){return lower_bound(op+1,op+tot+1,kuai(0,u,0))-op;}void addedge(int u,int v){e[++esz].r=v;e[esz].nxt=head[u];head[u]=esz;}ll lca(int u,int v){ll ans=dist[u]+dist[v];if(dist[u]<dist[v])swap(u,v);int d=dist[u]-dist[v];for(int i=0;d>>i;i++)if((d>>i)&1)u=fa[u][i];if(u==v)return ans-2*dist[u];for(int i=19;i>=0;--i)if(fa[u][i]!=fa[v][i])u=fa[u][i],v=fa[v][i];u=fa[u][0];return ans-2*dist[u];}ll solve(ll u,ll v){ll ans=0;bool flag=0;int ku=getkuai(u),kv=getkuai(v);if(dep[ku]<dep[kv])swap(ku,kv),swap(u,v);u=getid(op[ku].rt,u-op[ku].l+1);v=getid(op[kv].rt,v-op[kv].l+1);if(ku==kv)return lca(u,v);int d=dep[ku]-dep[kv];for(int i=0;d>>i;i++)if((d>>i)&1){ans+=dist[u]-dist[op[ku].rt];u=xfa[ku][i].conn;ans+=xdist[ku][i];ku=xfa[ku][i].ra;}if(ku==kv)return lca(u,v)+ans;ans+=dist[u]-dist[op[ku].rt],u=op[ku].rt;ans+=dist[v]-dist[op[kv].rt],v=op[kv].rt;for(int i=19;i>=0;--i)if(xfa[ku][i].ra!=xfa[kv][i].ra){ans+=dist[u]-dist[op[ku].rt],u=op[ku].rt;ans+=dist[v]-dist[op[kv].rt],v=op[kv].rt;u=xfa[ku][i].conn,v=xfa[kv][i].conn;ans+=xdist[ku][i]+xdist[kv][i];ku=xfa[ku][i].ra,kv=xfa[kv][i].ra;flag=true;}ans+=2;if(flag)ans+=dist[u]-dist[op[ku].rt]+dist[v]-dist[op[kv].rt];u=xfa[ku][0].conn,v=xfa[kv][0].conn;return ans+lca(u,v);}int main(){scanf("%d%d%d",&n,&m,&q);for(int i=1,u,v;i<n;++i)scanf("%d%d",&u,&v),addedge(u,v),addedge(v,u);dfs(1,0,1);for(int i=1;i<=n;++i)modify(root[i-1],root[i],1,n,dfn[i]);op[++tot]=kuai(1,size[1],1);now=size[1];ll v;int u;for(int i=1;i<=m;++i){scanf("%d%lld",&u,&v);int ra=getkuai(v);int conn=getid(op[ra].rt,v-op[ra].l+1);op[++tot]=kuai(now+1,now+size[u],u),now+=size[u];xfa[tot][0]=data(conn,ra),xdist[tot][0]=1;dep[tot]=dep[ra]+1;}for(int i=1;i<20;++i)for(int j=1;j<=tot;++j){xfa[j][i]=xfa[xfa[j][i-1].ra][i-1];xdist[j][i]=xdist[j][i-1]+dist[xfa[j][i-1].conn]-dist[op[xfa[j][i-1].ra].rt]+xdist[xfa[j][i-1].ra][i-1];}for(int i=1;i<=q;++i){ll u,v;scanf("%lld%lld",&u,&v);printf("%lld\n",solve(u,v));}}





0 0
原创粉丝点击