1. 程式人生 > >[HNOI2016]樹

[HNOI2016]樹

pri 樹根 can body put font pan 順序 input

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條邊。

如果看不懂可以看一下下面幾個博客

http://www.cnblogs.com/wfj2048/p/6416591.html

把每一個新添的子樹縮成一個點,那麽新樹就只有m+1點(模板樹算一個點)

每一次加樹就等於鏈接新樹中兩個點

判斷y在哪個點用二分,鏈接的邊權為兩個點代表的子樹根節點的距離

判斷這個新點連上的點對應模板樹的哪個點,需要判斷dfs序區間內的區間第k大,這要用到主席樹

查詢(x,y)時分清況:先求出(x,y)在模板樹的對應點(u,v),新樹上的w=LCA(p,q)

1.兩個屬同一個子樹,在模板樹求(u,v)距離

2.不屬於同一子樹(p,q),先求出在新樹上的距離,再加上u->u的子樹根的距離(模板樹),v同理

因為這樣算出的距離在w的子樹中可能多算,因為路徑不一定經過w的根

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 #include<cmath>
  6 using namespace std;
  7 typedef long long lol;
  8 struct ZYYS
  9 {
 10   lol rt,id,pre;
 11   lol l,r;
 12 }a[100005];
 13 lol pos,ch[6000005][2],sum[6000005],n,m,root[100005];
 14 lol ans;
 15 struct Tree
 16 {
 17   struct Node
 18   {
 19     lol next,to;
 20     lol dis;
 21   }edge[200005];
 22   lol head[100005],num,dep[100005],size[100005],id[100005],lx[100005],rx[100005],top[100005],cnt,son[100005],fa[100005];
 23   lol d[100005];
 24   void add(lol u,lol v,lol dis)
 25   {
 26     num++;
 27     edge[num].next=head[u];
 28     head[u]=num;
 29     edge[num].to=v;
 30     edge[num].dis=dis;
 31   }
 32   void dfs1(lol x,lol pa)
 33   {lol i;
 34     dep[x]=dep[pa]+1;
 35     size[x]=1;
 36     fa[x]=pa;
 37     for (i=head[x];i;i=edge[i].next)
 38       {
 39     lol v=edge[i].to;
 40     if (v!=pa)
 41       {
 42         d[v]=d[x]+edge[i].dis;
 43         dfs1(v,x);
 44         size[x]+=size[v];
 45         if (size[v]>size[son[x]]) son[x]=v;
 46       }
 47       }
 48   }
 49   void dfs2(lol x,lol pa,lol tp)
 50   {lol i;
 51     lx[x]=++cnt;
 52     id[cnt]=x;
 53     top[x]=tp;
 54     if (son[x])
 55       {
 56     dfs2(son[x],x,tp);
 57       }
 58     for (i=head[x];i;i=edge[i].next)
 59       {
 60     lol v=edge[i].to;
 61     if (v==pa||v==son[x]) continue;
 62     dfs2(v,x,v);
 63       }
 64     rx[x]=cnt;
 65   }
 66   lol gettop(lol x,lol y)
 67   {lol z;
 68     while (top[x]!=top[y])
 69       {
 70     z=top[x];
 71     x=fa[top[x]];
 72       }
 73     if (x==y) return z;
 74     return son[y];
 75   }
 76   lol lca(lol x,lol y)
 77   {
 78     while (top[x]!=top[y])
 79       {
 80     if (dep[top[x]]<dep[top[y]]) swap(x,y);
 81     x=fa[top[x]];
 82       }
 83     if (dep[x]>dep[y]) swap(x,y);
 84     return x;
 85   }
 86   lol dist(lol x,lol y)
 87   {
 88     return d[x]+d[y]-2*d[lca(x,y)];
 89   }
 90 }t1,t2;
 91 lol getid(lol k,lol r)
 92 {
 93   lol l=1,as=0;
 94   while (l<=r)
 95     {
 96       lol mid=(l+r)/2;
 97       if (a[mid].l<=k) as=mid,l=mid+1;
 98       else r=mid-1;
 99     }
100   return as;
101 }
102 void update(lol x,lol &y,lol l,lol r,lol k)
103 {
104   y=++pos;
105   ch[y][0]=ch[x][0];ch[y][1]=ch[x][1];
106   sum[y]=sum[x]+1;
107   if (l==r) return;
108   lol mid=(l+r)/2;
109   if (k<=mid) update(ch[x][0],ch[y][0],l,mid,k);
110   else update(ch[x][1],ch[y][1],mid+1,r,k);
111 }
112 lol query(lol x,lol y,lol l,lol r,lol k)
113 {
114   if (l==r) return l;
115   lol mid=(l+r)/2;
116   lol zyys=sum[ch[y][0]]-sum[ch[x][0]];
117   if (zyys<k) return query(ch[x][1],ch[y][1],mid+1,r,k-zyys);
118   else return query(ch[x][0],ch[y][0],l,mid,k);
119 }
120 int main()
121 {lol i,Q;
122   lol x,y,u,v;
123   cin>>n>>m>>Q;
124   for (i=1;i<=n-1;i++)
125     {
126       scanf("%lld%lld",&u,&v);
127       t1.add(u,v,1);
128       t1.add(v,u,1);
129     }
130   t1.dfs1(1,0);
131   t1.dfs2(1,0,1);
132   for (i=1;i<=n;i++)
133     update(root[i-1],root[i],1,n,t1.id[i]);
134   a[1].id=1;a[1].rt=1;a[1].l=1;a[1].r=n;
135   for (i=1;i<=m;i++)
136     {
137       scanf("%lld%lld",&x,&y);
138       a[i+1].id=i+1;a[i+1].rt=x;
139       a[i+1].l=a[i].r+1;
140       a[i+1].r=a[i+1].l+t1.size[x]-1;
141       lol z=getid(y,i);
142       a[i+1].pre=y=query(root[t1.lx[a[z].rt]-1],root[t1.rx[a[z].rt]],1,n,y-a[z].l+1);
143       t2.add(z,i+1,t1.d[y]-t1.d[a[z].rt]+1);
144       t2.add(i+1,z,t1.d[y]-t1.d[a[z].rt]+1);
145     }
146   t2.dfs1(1,0);t2.dfs2(1,0,1);
147   for (i=1;i<=Q;i++)
148     {
149       scanf("%lld%lld",&x,&y);
150       lol p=getid(x,m+1),q=getid(y,m+1);
151       lol w=t2.lca(p,q);
152       lol u=query(root[t1.lx[a[p].rt]-1],root[t1.rx[a[p].rt]],1,n,x-a[p].l+1);
153       lol v=query(root[t1.lx[a[q].rt]-1],root[t1.rx[a[q].rt]],1,n,y-a[q].l+1);
154       if (p==q)
155     {
156       printf("%lld\n",t1.dist(u,v));
157     }
158       else
159     {
160       if (p==w) swap(p,q),swap(u,v);
161       if (q==w)
162         {
163           x=t2.gettop(p,w);
164           ans=t2.d[p]-t2.d[x]+t1.d[u]-t1.d[a[p].rt];
165           u=a[x].pre;
166           ans+=t1.dist(u,v)+1;
167         }
168       else
169         {
170           ans=(t1.d[u]-t1.d[a[p].rt]+t1.d[v]-t1.d[a[q].rt]);
171           ans+=t2.dist(p,q);
172           x=t2.gettop(p,w);y=t2.gettop(q,w);
173           u=a[x].pre;v=a[y].pre;
174           ans+=(t1.d[a[w].rt]-t1.d[t1.lca(u,v)])*2;
175         }
176       printf("%lld\n",ans);
177     }
178     }
179 }

[HNOI2016]樹