P6374 「StOI-1」树上询问
题目描述
给定一棵 n 个点的无根树,有 q 次询问。
每次询问给一个参数三元组 (a,b,c) ,求有多少个 i 满足这棵树在以 i 为根的情况下 a 和 b 的 LCA 为 c 。
输入格式
第一行2个数,为 n 和 q 。
接下来 n-1 行,每行 2 个数,表示树的一条边。
接下来 q 行,每行 3 个数,为(a,b,c)。
输出格式
共 q 行,每行一个数,为对于每个三元组的 i 的个数。
输入输出样例
输入 #1
10 5
1 2
1 3
2 4
2 5
2 10
5 6
3 7
7 8
7 9
4 6 2
4 10 1
6 8 3
9 10 2
4 10 5
输出 #1
7
0
1
4
0
输入 #2
5 3
1 3
1 5
3 4
3 2
5 2 3
5 2 1
2 4 5
输出 #2
2
1
0
输入 #3
20 10
1 2
1 3
1 4
2 5
2 6
3 10
4 13
4 14
6 7
6 8
10 11
4 15
4 16
8 9
11 12
16 17
16 18
16 19
17 20
15 19 16
1 12 1
20 20 20
7 7 8
1 8 3
5 20 2
2 9 6
9 12 1
9 12 2
9 12 3
输出 #3
4
16
20
0
0
5
2
10
2
1
说明/提示
样例2解释
第一个查询的 ii 为 3 和 4。
第二个查询的 ii 为 1。
数据范围
思路:
由于本题并未指定一个根节点,且节点个数却到达了“5*105”个
so,不可能去枚举每一个点作为根节点
so,必须自行定义一个根节点,在进行判断
至于根节点可自行选择
对于本图而言以“9”为“a”,以“4”为“b”,以“2”为“c”
显而易见 qwq最后可以为根节点的则有“2”+“10”,“5”,“6”
其实可以简化成:
再转回第一幅图,则可知
其实最后只用处理“c”的子树即可
也就是将“c”的所有子树-“b”所在的“c”的那个子树而非以“b”为根节点的那棵树
就为可能的根节点数…………
你以为完了么???你放屁
其实还有两种情况
即(1):“a”,“b”都为“c”的子树且不在“c”的同一棵子树中
即:
对于此图,则…………去看代码吧…………
(2):“c”并不在“a”~“b”这条链中
即:
则直接输出“0”即可…………
至于怎么判断…………自己看代码…………再在草稿本上推算吧…………
#include <algorithm>
#include <iostream>
#include <cstring>
#include <vector>
#include <cstdio>
#include <queue>
#include <cmath>
#define LL long long
using namespace std;
const int N=5*1e5+100,M=1001;
int n,m,u,v,a,b,c,f[N][30],dis[N],cnt[N],high[N];
vector < int > q[N];
void dfs ( int rt,int fa,int h )
{
cnt[rt]=1;
f[rt][0]=fa;
high[rt]=h++;
int len=q[rt].size ( );
for ( int i=0;i<len;i++ )
{
int to=q[rt][i];
if ( to!=fa )
{
dfs ( to,rt,h );
cnt[rt]+=cnt[to]; //看每个数的节点数+其本身…………
}
}
}
int lca ( int x,int y )
{
if ( high[x]>high[y] ) swap ( x,y );
int c=high[y]-high[x],k=19,m=1<<k;
while ( c )
{
if ( c>=m ) y=f[y][k],c-=m;
m/=2,k--;
}
if ( x==y ) return x;
k=19;
while ( k>=0 ) { if ( f[x][k]!=f[y][k] ) x=f[x][k],y=f[y][k];k--; }
return f[x][0];
}
int find ( int x,int y ) //找出从x-->y的x在的那个子树的根节点
{
if ( x==y ) return 0;
for ( int i=19;i>=0;i-- ) if ( high[f[x][i]]>high[y] ) x=f[x][i];
return cnt[x];
}
int main ( )
{
scanf ( "%d %d",&n,&m );
for ( int i=1;i<n;i++ )
{
scanf ( "%d %d",&u,&v );
q[u].push_back ( v ),q[v].push_back (u);
}
dfs ( 1,0,1 );
for ( int j=1;j<=19;j++ ) for ( int i=1;i<=n;i++ ) f[i][j]=f[f[i][j-1]][j-1];
while ( m-- )
{
scanf ( "%d %d %d",&a,&b,&c );
int ca=lca ( a,c ),cb=lca ( b,c ),ab=lca ( a,b );
int fa=ca==c?find ( a,c ):0,fb=cb==c?find ( b,c ):0;
if ( lca (ab,c)!=ab ) printf ( "0\n" ); //如(2)
else if ( ab==c ) printf ( "%d\n",cnt[1]-fa-fb ); //如(1)
else if ( ca==c) printf ( "%d\n",cnt[c]-fa ); //如图1
else if ( cb==c) printf ( "%d\n",cnt[c]-fb ); //本质和图1相同
else printf ( "0\n" ); //如(2)
}
return 0;
}