您的位置:首页 > 其它

NOIP模拟(20171023)T2 一样远

2017-10-23 20:05 375 查看
求树上离给定两点a,b一样远的点的个数

点数n≤105,询问数m≤105

首先,如果a=b,那么n个点都是答案

如果a≠b,将从a到b的链提出来,易得链中点及其子树到a、b距离均相等

显然,我们不能暴力跳树高找中点,考虑倍增

注意当lca是链中点时lca的祖先节点及祖先节点的其他子树上的点也是答案

复杂度O(nlog2n+mlog2n)

#include<bits/stdc++.h>
#define LEN 100005
using namespace std;
inline int getint(){
int x=0,p=1;
char c=getchar();
while(!isdigit(c)){
if(c=='-')p=-1;
c=getchar();
}
while(isdigit(c)){
x=(x<<3)+(x<<1)+(c^'0');
c=getchar();
}
return x*p;
}
int n;
struct tree{
int fa[20],dep,size;
vector<int>road;
}t[LEN];
void dfs(int cur){
t[cur].size=1;
for(int i=0;i<t[cur].road.size();++i){
int v=t[cur].road[i];
if(v==t[cur].fa[0])continue;
t[v].fa[0]=cur;
t[v].dep=t[cur].dep+1;
dfs(v);
t[cur].size+=t[v].size;
}
}
void make_fa(){
for(int i=1;i<19;++i){
for(int j=1;j<=n;++j){
t[j].fa[i]=t[t[j].fa[i-1]].fa[i-1];
}
}
}
inline void work(int a,int b){
if((t[a].dep-t[b].dep)%2){
cout<<0<<"\n";
return;
}
if(a==b){
cout<<n<<"\n";
return;
}
if(t[a].dep==t[b].dep){
for(int i=18;i>=0;--i){
if(t[a].fa[i]!=t[b].fa[i]){
a=t[a].fa[i],b=t[b].fa[i];
}
}
cout<<n-t[a].size-t[b].size<<"\n";
}
else{
if(t[a].dep<t[b].dep)swap(a,b);
int left=(t[a].dep-t[b].dep)/2;
int lca,ta=a,tb=b;
for(int i=18;i>=0;--i){
if(t[t[a].fa[i]].dep>=t[b].dep)a=t[a].fa[i];
}
if(a==b)lca=b;
else{
for(int i=18;i>=0;--i){
if(t[a].fa[i]!=t[b].fa[i]){
a=t[a].fa[i],b=t[b].fa[i];
}
}
lca=t[a].fa[0];
}
a=ta,b=tb;
int dis=t[a].dep-t[lca].dep;
int need=dis-left-1;
for(int i=18;i>=0;--i){
if(need&(1<<i)){
a=t[a].fa[i];
}
}
cout<<t[t[a].fa[0]].size-t[a].size<<"\n";
}
}
int main(){
n=getint();
for(int i=1;i<n;++i){
int a=getint(),b=getint();
t[a].road.push_back(b);
t[b].road.push_back(a);
}
int root=1;
dfs(1);
make_fa();
int m=getint();
while(m--){
work(getint(),getint());
}
return 0;
}


ps:cout << endl 会TLE,强烈吐槽评测机
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: