bzoj3488: [ONTAK2010]Highways

 


3488: [ONTAK2010]Highways

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 157  Solved: 23
[Submit][Status][Discuss]

Description

Byteland is a small country, with cities connected by N-1 bidirectional roads. From each city there is just one way of reaching every other city using the road network, which causes severe traffic jams. For this reason several highways have been built; each highway connects some pair of cities. 
By a route we mean a sequence of roads and/or highways. All cities on a route should be distinct. For each pair of cities x,y there exists exactly one route which does not use any highway; we call such a route the main route between x and y . 
People going from a city x to a city y can either choose the main route or use some highway. In the latter case the route cannot intersect the main route except for the cities x and  y and must contain exactly one highway. 
Your task is to calculate the number of routes people can take between given pairs of cities. 

给一棵n个点的树以及m条额外的双向边
q次询问,统计满足以下条件的u到v的路径:
恰经过一条额外的边
不经过树上u到v的路径上的边

Input


The first line of input contains a single integer N(1<=N<=100000) - the number of cities in Byteland. Cities are numbered from 1 to n . Each of the next N -1 lines contains two integers Ai, Bi(1<=Ai,Bi<=N) meaning that cities Ai and Biare connected by a road. 
The next line contains an integer M(1<=M<=100000) - the number of highways. Each of the next m lines contains a description of a single highway. The next line contains an integer Q (1<=Q<=500000) - the number of queries. Each of the next Q lines contains a description of a query. Both highways and queries are given in the same format as the roads. 

Output

Your program should output exactly Q lines. The i-th line should contain the number of routes in the i-th query. 

Sample Input

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

Sample Output

1
4
2
2
 
题解
如果询问中u和v不是祖先的关系,这题实际上就是求u的子树中有多少条额外边连到v的子树。如果u是v的祖先,设p是u的孩子,p是v所在的子树,答案就是v的子树中的连的额外边的总数目-v的子树中连的另一端在p中的额外边的数目。
这样的话我们离线处理。每个节点的线段树是建立在dfs序上,我们自底向上合并,处理到某一个节点时,线段树中一段的值就是这个子树中的所有额外边的另一端连在了这一段上(因为所有子树已经被合并了进来)。这样对于一个询问u,v,在处理到u的时候查询u的线段树中v的子树的一段dfs序的值。如果有祖先关系的话也是差不多处理。
代码很丑
  1 {$S-}{$I-}{$R-}{$V-}
  2 program j01;
  3 const maxn=100086;maxq=500086;
  4 var head,root:array[0..maxn]of longint;
  5     q,next:array[0..2*maxn]of longint;
  6     q2,next2,id:array[0..maxq]of longint;
  7     head2:array[0..maxn]of longint;
  8     l,r:array[0..40*maxn]of longint;
  9     sum:array[0..40*maxn]of int64;
 10     fir,ed:array[0..maxn]of longint;
 11     ans:array[0..maxq]of int64;
 12     n,m,qu,tt,t2,u,v,i,j,tot,cnt,ll,rr:longint;
 13     fa:array[0..maxn,0..20]of longint;
 14     dep:array[0..maxn]of longint;
 15     dfn:array[0..maxn]of longint;
 16     bin:array[0..maxn]of longint;
 17 
 18 procedure swap(var a,b:longint);inline;
 19 var c:longint;
 20 begin
 21   c:=a;a:=b;b:=c;
 22 end;
 23 
 24 procedure add(const u,v:longint);inline;
 25 begin
 26   inc(tt);q[tt]:=v;next[tt]:=head[u];head[u]:=tt;
 27 end;
 28 
 29 procedure dfs(i,pre:longint);
 30 var j:longint;
 31 begin
 32   for j:=1 to bin[dep[i]] do
 33     fa[i,j]:=fa[fa[i,j-1],j-1];
 34   inc(tot);fir[i]:=tot;
 35   dfn[tot]:=i;
 36   j:=head[i];
 37   while j>0 do
 38   begin
 39     if q[j]<>pre then
 40     begin
 41       dep[q[j]]:=dep[i]+1;fa[q[j],0]:=i;
 42       dfs(q[j],i);
 43     end;
 44     j:=next[j];
 45   end;
 46   ed[i]:=tot;
 47 end;
 48 
 49 procedure ins(var i:longint;ll,rr,ps:Longint);
 50 var mid:longint;
 51 begin
 52   if i=0 then
 53   begin
 54     inc(cnt);i:=cnt;
 55   end;
 56   inc(sum[i]);mid:=(ll+rr)div 2;
 57   if ll=rr then exit;
 58   if ps<=mid then ins(l[i],ll,mid,ps) else ins(r[i],mid+1,rr,ps);
 59 end;
 60 
 61 procedure add2(const u,v,i:longint);inline;
 62 begin
 63   inc(t2);q2[t2]:=v;next2[t2]:=head2[u];id[t2]:=i;head2[u]:=t2;
 64 end;
 65 
 66 function merge(x,y:longint):longint;
 67 begin
 68   if(x=0)or(y=0)then exit(x+y);
 69   sum[x]:=sum[x]+sum[y];
 70   l[x]:=merge(l[x],l[y]);
 71   r[x]:=merge(r[x],r[y]);
 72   exit(x);
 73 end;
 74 
 75 function ask(i,lt,rt:longint):int64;
 76 var mid:longint;
 77 begin
 78   if(ll<=lt)and(rt<=rr) then exit(sum[i]);
 79   mid:=(lt+rt)div 2;ask:=0;
 80   if ll<=mid then ask:=ask(l[i],lt,mid);
 81   if mid+1<=rr then ask:=ask+ask(r[i],mid+1,rt);
 82 end;
 83 
 84 function find(const i,d:longint):longint;inline;
 85 var j,x:longint;
 86 begin
 87   x:=i;
 88   if d=0 then exit(i);
 89   for j:=bin[d] downto 0 do
 90     if d and(1 shl j)>0 then x:=fa[x,j];
 91   exit(x);
 92 end;
 93 
 94 procedure work;
 95 var i,j,k,x:longint;
 96 begin
 97   for x:=tot downto 1 do
 98   begin
 99     i:=dfn[x];
100     j:=head2[i];
101     while j>0 do
102     begin
103       if (fir[i]<=ed[q2[j]])and(fir[i]>=fir[q2[j]]) then
104       begin
105         k:=find(i,dep[i]-dep[q2[j]]-1);
106         ll:=fir[k];rr:=ed[k];
107         ans[id[j]]:=sum[root[i]]-ask(root[i],1,n);
108       end else
109       begin
110         ll:=fir[q2[j]];rr:=ed[q2[j]];
111         ans[id[j]]:=ask(root[i],1,n);
112       end;
113       j:=next2[j];
114     end;
115     if x<>1 then root[fa[i,0]]:=merge(root[fa[i,0]],root[i]);
116   end;
117 end;
118 
119 begin
120   readln(n);
121   bin[1]:=0;
122   for i:=2 to n do
123     if i and(i-1)=0 then bin[i]:=bin[i-1]+1 else bin[i]:=bin[i-1];
124   fillchar(head,sizeof(head),0);tt:=0;
125   for i:=1 to n-1 do
126   begin
127     readln(u,v);
128     add(u,v);add(v,u);
129   end;
130   tot:=0;dfs(1,0);
131   readln(m);cnt:=0;
132   for i:=1 to m do
133   begin
134     readln(u,v);
135     ins(root[u],1,n,fir[v]);ins(root[v],1,n,fir[u]);
136   end;
137   readln(qu);
138   fillchar(head2,sizeof(head2),0);t2:=0;
139   for i:=1 to qu do
140   begin
141     readln(u,v);
142     if(fir[u]<=fir[v])and(fir[v]<=ed[u])then swap(u,v);
143     add2(u,v,i);
144   end;
145   work;
146   for i:=1 to qu do
147   begin
148     writeln(ans[i]+1);
149   end;
150 end.
View Code

 

 
posted @ 2017-03-20 21:02  OldJang  阅读(239)  评论(0编辑  收藏  举报