这题是道签到题。
容易想到把所有的 a , b a,b a,b 拿出来从小到大排序。然后枚举最小值,确定最大值。
先讲一种很菜的 O ( n log 2 n ) O(n\log_2 n) O(nlog2n) 做法。考虑 二分 最大值的位置。比这个最大值大的所有 a a a 显然都要跳到它们对应的 b b b 处,可能还会出现不合法的情况。因此可以先用 后缀 维护出排序后下标在 [ i , 2 n ] [i,2n] [i,2n] 中的 a a a 对应的 b b b 的最大值,和 a a a 的个数。
其实还可以 O ( n ) O(n) O(n) 双指针 。因为最小值指针右移时,最大值指针不会左移。
如果忍受不了排序那个 O ( n log 2 n ) O(n\log_2 n) O(nlog2n) ,可以 双关键字桶排 。
考虑先不管上下限,求出一组解,然后再进行调整。
求这一组解很简单,可以令第一行、第一列全部为 0 0 0 。然后按顺序求出其他值即可。
怎么调整?发现对于任意一个 2 × 2 2\times 2 2×2 的矩阵,我们把其中的两个 − 1 -1 −1 ,另外两个 + 1 +1 +1 ,它们的和不变,仍然满足 b b b 的限制。如果只修改一行,可以把这一行上列编号为奇数的元素 + x +x +x ,列编号为偶数的元素 − x -x −x 。对于每一列也是同理。
但是为什么这样调整可以达到合法的状态?
发现根据 b b b 矩阵我们可以列出 ( n − 1 ) ( m − 1 ) (n-1)(m-1) (n−1)(m−1) 个方程,此时距离解出 a a a 的值还差 n + m − 1 n+m-1 n+m−1 个方程。因此如果我们确定了第一行和第一列所有元素的值,矩阵中的其它 a a a 的值就是固定的了。而显然我们可以通过操作让第一行、第一列的每一个元素达到任意取值。
那么我们怎么调整?
设第 i i i 行调整的数为 c i c_i ci ,第 i i i 列调整的数为 d i d_i di 。那么
a i , j ′ = a i , j + ( − 1 ) j + 1 c i + ( − 1 ) i + 1 d j a'_{i,j}=a_{i,j} + (-1)^{j+1} c_{i} + (-1)^{i+1} d_{j} ai,j′=ai,j+(−1)j+1ci+(−1)i+1dj
发现当 i , j i,j i,j 的奇偶性相同时, c i , d j c_i,d_j ci,dj 前面的系数相同。这时就是 和分约束 了,做不了。
因为我们只要让相邻的两个数 c , d c,d c,d 的系数不同即可,因此可以
a i , j ′ = a i , j + ( − 1 ) i + j − 1 c i + ( − 1 ) i + j d i a'_{i,j}=a_{i,j} +(-1)^{i+j-1}c_i + (-1)^{i+j}d_i ai,j′=ai,j+(−1)i+j−1ci+(−1)i+jdi
然后就是 差分约束 啦。
由于 差分约束 中我们建出来的是一个 完全二分图 ,因此用 B e l l m a n − F o r d Bellman-Ford Bellman−Ford 也可以跑得很快。
不难想到, f ( u , G ) f(u,G) f(u,G) 表示图 G G G 中有多少个点 v v v 满足同时存在 u → v u\to v u→v 和 v → u v\to u v→u 且这两条路径上的点的编号都不小于 v v v 。
那么可以设 g i , j , k g_{i,j,k} gi,j,k 表示当前的图中是否存在路径 i → j i\to j i→j 满足路径上的点的编号都不小于 k k k 。
如果用 F l o y d Floyd Floyd 做,可以省掉 k k k 这一维,从大到小枚举中转点 k k k 即可。
发现 G G G 很烦,想办法怎么一次 F l o y d Floyd Floyd 做完。
删边有点难搞,可以考虑把边按编号从大到小插入。发现我们的状态 g g g 记录一个 b o o l bool bool 值,比较浪费。于是设 h i , j h_{i,j} hi,j 表示当前的图中,所有 i → j i\to j i→j 的路径中 最大 的 路径上最小的边的编号 (省略 k k k 这一维)。
用 F l o y d Floyd Floyd 做,可以求出一个答案的 差分数组 ,求一个 后缀和 就好了。
虽然时间复杂度是 O ( n 3 ) O\left(n^3\right) O(n3) ,但是这却是这题最快的解法。
尽管如此,可能还要卡卡常。下面给出一个小优化:
F l o y d Floyd Floyd 时, i , j > k i,j>k i,j>k 的情况更新状态 h i , j h_{i,j} hi,j 没有意义了。
证明:
因为 i , j i,j i,j 不会再当中转点了,且这两个点都不会作为 k k k 对答案造成贡献了,所以更新状态 h i , j h_{i,j} hi,j 没有意义。
D a y 2 Day\; 2 Day2 签到题,然而我不会。
先考虑一条链上怎么做。我们先跳到 S → T S\to T S→T 中离 S S S 最近的颜色为 P 1 P_1 P1 的点,然后跳离这个点最近的 P 2 P_2 P2 ,接着跳 P 3 P_3 P3 ……
那么现在要维护每个点后第一个颜色为 P 1 P_1 P1 的点,以及这个点在宝石收集器中的下一种颜色对应的点。由于要跳很多步,用倍增优化跳的过程。
现在放到树上,假设我们现在能 O ( 1 ) O(1) O(1) 求出任意一个点到根的路径上离它最近的某种颜色的点,剩下的怎么做呢?老套路,把 S → T S\to T S→T 的路径分成 S → l c a , l c a → T S\to lca,lca\to T S→lca,lca→T 。
先求在 S → l c a S\to lca S→lca 上最多能收集多少个宝石。这不是直接倍增往上跳就行了吗?
再求在 l c a → T lca\to T lca→T 上最多能收集多少个宝石。不好做,于是把路径反过来。二分收集到的最后一颗宝石,预处理出每个点在宝石收集器中的上一种颜色对应的点,也是倍增优化。这样就可以 O ( log 2 c log 2 n ) O(\log_2 c\log_2 n) O(log2clog2n) 地求了。
发现这时这两部分可以分开求。
于是把询问离线,遍历这棵树两次,每次都动态维护当前点到根的路径上离它最近的某种颜色的点。第一次遍历时求出 S → l c a S\to lca S→lca 这部分的答案,第二次遍历时求出 l c a → T lca\to T lca→T 这部分的答案,这样就可以了。
时间复杂度 O ( n log 2 n + q log 2 c log 2 n ) O(n\log_2 n+q\log_2 c\log_2 n) O(nlog2n+qlog2clog2n) 。
P.S:这道题还可以用 点分治 做到 O ( n log 2 n + q log 2 n ) O(n\log_2 n+q\log_2 n) O(nlog2n+qlog2n) 。
一眼看上去就是状压 D P DP DP 。
设 f s , i , j , k f_{s,i,j,k} fs,i,j,k 表示状态 s s s 中的队伍还没有公布,上一个公布的队伍为 i i i , b i = j b_i=j bi=j ,剩余的 m m m 值为 k k k 。
空间复杂度 O ( 2 n m 2 n ) O\left(2^n m^2 n\right) O(2nm2n) ,时间复杂度 O ( 2 n − 2 m 2 n 2 ) O\left(2^{n-2}m^2 n^2\right) O(2n−2m2n2) ,勉强能拿 40 40 40 分,还不如暴力 O ( n × n ! ) O(n\times n!) O(n×n!) 。
考虑消掉一维,去掉 j j j 。由于 b b b 按公布顺序单调不下降,可以在每次加入一个队伍 x x x 之后强制把没有公布的队伍的 b b b 都加上 max ( a i − a x + [ x > i ] , 0 ) \max\left(a_i-a_x+[x>i],0\right) max(ai−ax+[x>i],0) ,这样就行了。
空间复杂度 O ( 2 n m n ) O\left(2^nmn \right) O(2nmn),时间复杂度 O ( 2 n − 2 m n 2 ) O\left(2^{n-2}mn^2\right) O(2n−2mn2) (实际上时间肯定是跑不满的)。
考场上觉得这题可做,就拼命弄这题,结果因为一些地方想错了,最后只拿到树的 15 15 15 分。
发现对于每个点 x x x ,图中必定存在一条链,使得链上包含所有在 D x D_x Dx 中的点。若构建一个新图 G 1 G_1 G1 ,若原图 G 0 G_0 G0 中 x x x 是 D y D_y Dy 中离 y y y 最近的点(即走最少的步数能到达 y y y 的点),就在 G 1 G_1 G1 中加入一条边 x → y x\to y x→y 。发现 G 1 G_1 G1 会变成一棵根节点是 1 1 1 的树。事实上,这就是 支配树 。
怎么建这棵树?有 O ( m ) O(m) O(m) 的做法,但是因为这题允许我们 O ( n 2 ) O\left(n^2\right) O(n2) 建树,就不如用好写的 O ( n 2 ) O\left(n^2\right) O(n2) 做法了。
可以从 1 1 1 到 n n n 枚举一个点 i i i 。然后从 1 1 1 出发,不经过 i i i 遍历整个图。若最后点 j j j 没有被遍历到,那么 i ∈ D j i\in D_j i∈Dj 。显然 i i i 的父亲就是 D i D_i Di 中 ∣ D ∣ |D| ∣D∣ 最小的点。
接下来考虑怎么求答案。
显然就是求加入 s → t s\to t s→t 后有多少个点的受支集合发生改变(显然受支集合只会减小,即去除某些元素)。假设某个点 i i i 在支配树上的子树中的所有点的 D D D 发生了改变(这显然是因为 D i D_i Di 中一些元素不在 D s D_s Ds 中),可以发现 i i i 要满足两个条件:
可以把原图中的边反向,对于点 i i i ,求出有哪些点 j j j 不经过 f a j fa_j faj 就能到达 i i i 。就可以求出所有满足 条件2 的点了。
枚举这些点,筛选出其中满足 条件1 的点即可。
但是这些点可能已经在支配树上形成祖孙关系了,这个差分处理即可。
时间复杂度 O ( n 2 + n q ) O\left(n^2 +nq \right) O(n2+nq) 。
#include
#include
using namespace std;
#define fo(i,l,r) for(i=l;i<=r;++i)
#define M 2000005
#define N 1000005
const int inf=1000000001;
int m,s,a[N][2],minn[M],maxx[M],sum[M];bool state[M];
struct node{
int num,id;bool type;}b[M];
bool cmp(node x,node y){
return x.num<y.num;}
inline int mymin(int x,int y){
return x<y?x:y;}
inline int mymax(int x,int y){
return x>y?x:y;}
int main()
{
freopen("card.in","r",stdin);
freopen("card.out","w",stdout);
register int i;
int n,ans=inf,l,r,mid,L=1,res;
scanf("%d%d",&n,&m);
fo(i,1,n) scanf("%d",&a[i][0]),b[++s]=(node){
a[i][0],i,0};
fo(i,1,n) scanf("%d",&a[i][1]),b[++s]=(node){
a[i][1],i,1};
sort(b+1,b+s+1,cmp);
fo(i,1,s) a[b[i].id][b[i].type]=i;
minn[s+1]=inf;
for(i=s;i;--i)
{
if(b[i].type)
minn[i]=minn[i+1],maxx[i]=maxx[i+1],sum[i]=sum[i+1];
else
{
minn[i]=mymin(minn[i+1],a[b[i].id][1]);
maxx[i]=mymax(maxx[i+1],a[b[i].id][1]);
sum[i]=sum[i+1]+1;
}
}
fo(i,1,s)
{
if(b[i].type&&!state[b[i].id]) --m,state[b[i].id]=1;
if(m<0) goto end;
l=L,r=s,res=-1;
while(l<=r)
{
mid=l+r>>1;
if(minn[mid+1]<i||maxx[mid+1]>mid||sum[mid+1]-(b[i].type&&a[b[i].id][0]>mid?1:0)>m) l=mid+1;
else r=mid-1,res=mid;
}
if(res>0&&b[res].num-b[i].num<ans) ans=b[res].num-b[i].num;
end:
if(b[i].type)
{
if(a[b[i].id][0]<i) break;
if(a[b[i].id][0]>L) L=a[b[i].id][0];
++m,state[b[i].id]=0;
}
else
{
if(a[b[i].id][1]<i) break;
if(a[b[i].id][1]>L) L=a[b[i].id][1];
--m,state[b[i].id]=1;
}
}
printf("%d\n",ans);
return 0;
}
#include
using namespace std;
#define fo(i,l,r) for(i=l;i<=r;++i)
#define fd(i,r,l) for(i=r;i>=l;--i)
#define N 305
char p[15],buf[100005],*l=buf,*r=buf;
inline char gc()
{
return l==r&&(r=(l=buf)+fread(buf,1,100005,stdin),l==r)?EOF:*l++;}
inline void read(int &k)
{
char ch;while(ch=gc(),ch<'0'||ch>'9');k=ch-48;
while(ch=gc(),ch>='0'&&ch<='9') k=k*10+ch-48;
}
inline void print(int x)
{
if(!x) putchar('0');
else
{
int len=0;
while(x) p[++len]=x%10+48,x/=10;
for(;len;--len) putchar(p[len]);
}
putchar(' ');
}
int a[N][N],b[N][N],wa[N][N],wb[N][N],fa[N],fb[N];
inline void mymin(int &x,int y){
if(x>y) x=y;}
int main()
{
freopen("matrix.in","r",stdin);
freopen("matrix.out","w",stdout);
register int i,j;
int T,n,m,s,x,y;
bool flag;
read(T);
while(T--)
{
read(n),read(m);
for(i=1;i<n;++i)
for(j=1;j<m;++j) read(b[i][j]);
fo(i,1,n) a[i][1]=0;
fo(i,1,m) a[1][i]=0;
fo(i,2,n) fo(j,2,m) a[i][j]=b[i-1][j-1]-a[i][j-1]-a[i-1][j]-a[i-1][j-1];
s=n+m;
fo(i,1,n) fo(j,1,m) wa[i][j]=wb[j][i]=0x3f3f3f3f;
fo(i,1,n) fa[i]=0;
fo(i,1,m) fb[i]=0;
fo(i,1,n) fo(j,1,m)
{
if(i+j&1) // d[j]-c[i]
{
mymin(wa[i][j],a[i][j]),
mymin(wb[j][i],1000000-a[i][j]);
}
else // c[i]-d[j]
{
mymin(wb[j][i],a[i][j]),
mymin(wa[i][j],1000000-a[i][j]);
}
}
fo(x,1,s)
{
flag=1;
fo(i,1,n) fo(j,1,m)
if(fa[i]>fb[j]+wb[j][i])
fa[i]=fb[j]+wb[j][i],flag=0;
fo(i,1,m) fo(j,1,n)
if(fb[i]>fa[j]+wa[j][i])
fb[i]=fa[j]+wa[j][i],flag=0;
if(flag) break;
}
if(x>s) goto out;
fo(i,1,n) fo(j,1,m)
{
a[i][j]=i+j&1?a[i][j]+fa[i]-fb[j]:a[i][j]-fa[i]+fb[j];
if(a[i][j]<0||a[i][j]>1000000) goto out;
}
puts("YES");
fo(i,1,n)
{
fo(j,1,m) print(a[i][j]);
putchar('\n');
}
continue;
out:puts("NO");
}
return 0;
}
#include
using namespace std;
#define M 200005
#define N 1005
char p[15],buf[100005],*pl=buf,*pr=buf;
inline char gc()
{
return pl==pr&&(pr=(pl=buf)+fread(buf,1,100005,stdin),pl==pr)?EOF:*pl++;}
inline void read(int &k)
{
char ch;while(ch=gc(),ch<'0'||ch>'9');k=ch-48;
while(ch=gc(),ch>='0'&&ch<='9') k=k*10+ch-48;
}
inline void print(int x)
{
if(!x) putchar('0');
else
{
int len=0;
while(x) p[++len]=x%10+48,x/=10;
for(;len;--len) putchar(p[len]);
}
putchar(' ');
}
int f[N][N],ans[M];
inline int mymin(int x,int y){
return x<y?x:y;}
inline void mymax(int &x,int y){
if(x<y) x=y;}
int main()
{
freopen("graph.in","r",stdin);
freopen("graph.out","w",stdout);
register int i,j,k,tmp;
int x,y,n,m;
read(n),read(m);
for(i=1;i<=m;++i) read(x),read(y),f[x][y]=i;
for(k=n;k;--k)
{
for(i=k+1;i<=n;++i) ++ans[mymin(f[i][k],f[k][i])];
for(i=1;i<k;++i) if(f[i][k])
for(j=1;j<=n;++j)
mymax(f[i][j],mymin(f[i][k],f[k][j]));
for(i=k+1;i<=n;++i) if(f[i][k])
for(j=1;j<k;++j)
mymax(f[i][j],mymin(f[i][k],f[k][j]));
// i,j>k 因为 i,j 不会再当中转点了,且这两个点都不会作为 k 对答案造成贡献了,所以没有意义
}
ans[m+1]=n;
for(i=m;i;--i) ans[i]+=ans[i+1];
for(i=1;i<=m+1;++i) print(ans[i]);
return 0;
}
#include
#include
using namespace std;
char p[15],buf[100005],*pl=buf,*pr=buf;
inline char gc()
{
return pl==pr&&(pr=(pl=buf)+fread(buf,1,100005,stdin),pl==pr)?EOF:*pl++;}
inline void read(int &k)
{
char ch;while(ch=gc(),ch<'0'||ch>'9');k=ch-48;
while(ch=gc(),ch>='0'&&ch<='9') k=k*10+ch-48;
}
inline void print(int x)
{
if(!x) putchar('0');
else
{
int len=0;
while(x) p[++len]=x%10+48,x/=10;
for(;len;--len) putchar(p[len]);
}
putchar('\n');
}
#define fo(i,l,r) for(i=l;i<=r;++i)
#define M 400005
#define N 200005
#define C 50005
int fir[N],to[M],nex[M],w[N],num[C],id[C],las[C],f[N][18],g[N][18],h[N][18],dep[N],c,q,s,l,r,mid,now,res;
struct node{
int st,ed,lca,mid,ans;}a[N];
vector<int>qry1[N],qry2[N];
inline void inc(int x,int y)
{
to[++s]=y,nex[s]=fir[x],fir[x]=s;
to[++s]=x,nex[s]=fir[y],fir[y]=s;
}
void dfs(int k)
{
int i,tmp=las[w[k]];
dep[k]=dep[f[k][0]]+1;
g[k][0]=las[num[id[w[k]]+1]],
h[k][0]=id[w[k]]?las[num[id[w[k]]-1]]:0;
las[w[k]]=k;
for(i=fir[k];i;i=nex[i])
if(to[i]!=f[k][0])
f[to[i]][0]=k,dfs(to[i]);
las[w[k]]=tmp;
}
inline void swap(int &x,int &y){
int z=x;x=y,y=z;}
inline int getlca(int u,int v)
{
if(dep[u]<dep[v]) swap(u,v);
for(int i=17;i>=0;--i)
if(dep[f[u][i]]>=dep[v])
u=f[u][i];
if(u==v) return u;
for(int i=17;i>=0;--i)
if(f[u][i]!=f[v][i])
u=f[u][i],v=f[v][i];
return f[u][0];
}
void solveL(int k)
{
int i,j,tmp;
for(i=0;i<qry1[k].size();++i)
{
now=qry1[k][i],
tmp=w[k]==num[1]?k:las[num[1]];
for(j=17;j>=0;--j)
if(dep[g[tmp][j]]>=dep[a[now].lca])
tmp=g[tmp][j];
a[now].mid=dep[tmp]>=dep[a[now].lca]?w[tmp]:0;
}
tmp=las[w[k]],las[w[k]]=k;
for(i=fir[k];i;i=nex[i])
if(to[i]!=f[k][0]) solveL(to[i]);
las[w[k]]=tmp;
}
void solveR(int k)
{
int i,j,tmp;
for(i=0;i<qry2[k].size();++i)
{
now=qry2[k][i],l=id[a[now].mid]+1,r=c,res=l-1;
while(l<=r)
{
mid=l+r>>1,
tmp=w[k]==num[mid]?k:las[num[mid]];
for(j=17;j>=0;--j)
if(dep[h[tmp][j]]>=dep[a[now].lca])
tmp=h[tmp][j];
if(dep[tmp]>=dep[a[now].lca]&&id[w[tmp]]<=id[a[now].mid]+1) res=mid,l=mid+1;
else r=mid-1;
}
a[now].ans=res;
}
tmp=las[w[k]],las[w[k]]=k;
for(i=fir[k];i;i=nex[i])
if(to[i]!=f[k][0]) solveR(to[i]);
las[w[k]]=tmp;
}
int main()
{
freopen("gem.in","r",stdin);
freopen("gem.out","w",stdout);
register int i;
int j,n,m,x,y;
read(n),read(m),read(c);
fo(i,1,c) read(num[i]),id[num[i]]=i;
fo(i,1,n) read(w[i]);
for(i=1;i<n;++i) read(x),read(y),inc(x,y);
dfs(1);
fo(j,1,17) fo(i,1,n)
f[i][j]=f[f[i][j-1]][j-1],
g[i][j]=g[g[i][j-1]][j-1],
h[i][j]=h[h[i][j-1]][j-1];
read(q);
fo(i,1,q)
read(a[i].st),read(a[i].ed),
a[i].lca=getlca(a[i].st,a[i].ed),
qry1[a[i].st].push_back(i),
qry2[a[i].ed].push_back(i);
fo(i,1,m) las[i]=0;solveL(1);
fo(i,1,m) las[i]=0;solveR(1);
fo(i,1,q) print(a[i].ans);
return 0;
}
#include
using namespace std;
#define fo(i,l,r) for(i=l;i<=r;++i)
#define fd(i,r,l) for(i=r;i>=l;--i)
#define M 505
#define N 15
long long f[8195][N][M];
int a[N];
int main()
{
freopen("ranklist.in","r",stdin);
freopen("ranklist.out","w",stdout);
register int k,j,i;
int s,t,len,n,m,S,tmp,max=0;
long long ans=0;
scanf("%d%d",&n,&m),a[0]=-1;
fo(i,1,n) scanf("%d",a+i);
fo(i,1,n) if(a[i]>a[max]) max=i;
S=(1<<n)-1;
fo(i,1,n)
{
tmp=n*(a[max]-a[i]+(max<i));
if(tmp<=m) f[S^1<<i-1][i][m-tmp]=1;
}
fd(s,S-1,1)
{
len=0;
fo(i,1,n) if(s&1<<i-1) ++len;
fo(i,1,n) if(!(s&1<<i-1))
fo(k,1,n) if(s&1<<k-1)
{
tmp=(a[i]-a[k]+(i<k))*len;
t=s^1<<k-1;
if(tmp<0) tmp=0;
fo(j,tmp,m) if(f[s][i][j])
f[t][k][j-tmp]+=f[s][i][j];
}
}
fo(i,1,n) fo(j,0,m) ans+=f[0][i][j];
printf("%lld\n",ans);
return 0;
}
#include
#include
using namespace std;
#define fo(i,l,r) for(i=l;i<=r;++i)
#define M 6005
#define N 3005
struct graph
{
int fir[N],to[M],nex[M],s;
inline void inc(int x,int y)
{
to[++s]=y,nex[s]=fir[x],fir[x]=s;}
}G,F,D_tree;
struct node
{
int D[N],siz;
inline void inc(int x){
D[++siz]=x;}
}a[N],list[N];
int fa[N],vis[N],siz[N],dfn[N],sum[N],ord,time;
bool b[N],in[N];
void dfs1(int k)
{
vis[k]=time;
for(int i=G.fir[k];i;i=G.nex[i])
if(b[G.to[i]]&&vis[G.to[i]]<time)
dfs1(G.to[i]);
}
void dfs2(int k)
{
vis[k]=time,list[k].inc(time);
for(int i=F.fir[k];i;i=F.nex[i])
if(b[F.to[i]]&&vis[F.to[i]]<time)
dfs2(F.to[i]);
}
void dfs3(int k)
{
siz[k]=1,dfn[k]=++ord;
for(int i=D_tree.fir[k];i;i=D_tree.nex[i])
dfs3(D_tree.to[i]),siz[k]+=siz[D_tree.to[i]];
}
int main()
{
freopen("dominator.in","r",stdin);
freopen("dominator.out","w",stdout);
register int i,j;
int n,m,q,x,y,ans,k;
scanf("%d%d%d",&n,&m,&q);
fo(i,1,m)
scanf("%d%d",&x,&y),
G.inc(x,y),F.inc(y,x);
fo(i,1,n) b[i]=1;
fo(i,2,n)
{
a[i].inc(1);
time=i,b[i]=0,
dfs1(1),vis[i]=i;
fo(j,2,n) if(vis[j]<i)
a[j].inc(i);
b[i]=1;
}
fo(i,2,n)
{
fa[i]=a[i].D[1];
fo(j,2,a[i].siz)
if(a[a[i].D[j]].siz>a[fa[i]].siz)
fa[i]=a[i].D[j];
}
fo(i,2,n) D_tree.inc(fa[i],i);
dfs3(1);
fo(i,1,n) vis[i]=0;
fo(i,2,n)
{
time=i,b[fa[i]]=0;
dfs2(i),b[fa[i]]=1;
}
b[0]=1;
while(q--)
{
scanf("%d%d",&x,&y),ans=0;
fo(i,1,n) sum[i]=0;
i=x,b[1]=0;while(i>1) b[i]=0,i=fa[i];
fo(j,1,list[y].siz)
{
k=list[y].D[j];
if(b[fa[k]]) ++sum[dfn[k]],--sum[dfn[k]+siz[k]];
}
fo(j,1,n)
{
sum[j]+=sum[j-1];
if(sum[j]) ++ans;
}
printf("%d\n",ans);
i=x,b[1]=1;while(i>1) b[i]=1,i=fa[i];
}
return 0;
}