[NOIP模拟赛]约会date LCA(顺便填坑)

来源:互联网 发布:淘宝云客服招聘 编辑:程序博客网 时间:2024/05/21 22:55

这道题也算是厉害了,改了整整俩小时最后发现是深信的LCA打错了,悲伤啊!信仰崩塌了!

顺便复习LCA,给出模板

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
void init(){//p[i][j]表示i节点2^j的祖先
    int j;
    for(j=0;(1<<j)<=n;j++)
        pos(i,1,n)
            p[i][j]=-1;
    pos(i,1,n)
        p[i][0]=fa[i];
    for(j=1;(1<<j)<=n;j++)
        pos(i,1,n)
            if(p[i][j-1]!=-1)
                p[i][j]=p[p[i][j-1]][j-1];//i的2^j祖先即为2^(j-1)祖先的2^(j-1)祖先
}
int lca(int a,int b){
    int i;
    if(dep[a]<dep[b]) swap(a,b);//深度深的先爬
    for(i=0;(1<<i)<=dep[a];i++);
    i--;
    for(int j=i;j>=0;j--)
        if(dep[a]-(1<<j)>=dep[b])
            a=p[a][j];//爬到等高
    if(a==b) return a;//如果在一条链上,直接返回
    for(int j=i;j>=0;j--){
        if(p[a][j]!=-1&&p[a][j]!=p[b][j]){
            a=p[a][j];b=p[b][j];//两边一起爬,直到爬到LCA
        }
    }
    return fa[a];
}

这道题的题解是这样的:

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<queue>
#include<cmath>
#define pos(i,a,b) for(int i=(a);i<=(b);i++)
using namespace std;
#define N 101000
int n,m;
struct haha{
    int next,to;
}edge[N*2];
int head[N],cnt=1;
void add(int u,int v){
    edge[cnt].to=v;edge[cnt].next=head[u];head[u]=cnt++;
}
int dep[N],fa[N],size[N];
int p[N][22];
void dfs(int x){
    size[x]=1;
    for(int i=head[x];i;i=edge[i].next){
        int to=edge[i].to;
        if(fa[x]!=to){
            fa[to]=x;dep[to]=dep[x]+1;
            dfs(to);size[x]+=size[to];
        }
    }
}
void init(){//p[i][j]表示i节点2^j的祖先
    int j;
    for(j=0;(1<<j)<=n;j++)
        pos(i,1,n)
            p[i][j]=-1;
    pos(i,1,n)
        p[i][0]=fa[i];
    for(j=1;(1<<j)<=n;j++)
        pos(i,1,n)
            if(p[i][j-1]!=-1)
                p[i][j]=p[p[i][j-1]][j-1];//i的2^j祖先即为2^(j-1)祖先的2^(j-1)祖先
}
int lca(int a,int b){
    int i;
    if(dep[a]<dep[b]) swap(a,b);//深度深的先爬
    for(i=0;(1<<i)<=dep[a];i++);
    i--;
    for(int j=i;j>=0;j--)
        if(dep[a]-(1<<j)>=dep[b])
            a=p[a][j];//爬到等高
    if(a==b) return a;//如果在一条链上,直接返回
    for(int j=i;j>=0;j--){
        if(p[a][j]!=-1&&p[a][j]!=p[b][j]){
            a=p[a][j];b=p[b][j];//两边一起爬,直到爬到LCA
        }
    }
    return fa[a];
}
int get(int x,int anc,int num){
    int i;
    for(i=0;(1<<i)<=dep[x];i++);
    i--;
    for(int j=20;j>=0;j--)
        if(dep[x]-(1<<j)>=dep[anc]+num)
            x=p[x][j];
    return x;
}
int main(){
    //freopen("date.in","r",stdin);
    //freopen("date.out","w",stdout);
    scanf("%d",&n);
    pos(i,1,n-1){
        int x,y;scanf("%d%d",&x,&y);
        add(x,y);add(y,x);
    }
    dfs(2);//cout<<fa[2];
    init();
    scanf("%d",&m);//system("pause");
    pos(i,1,m){
        int x,y;scanf("%d%d",&x,&y);
        int anc=lca(x,y);
        int dis=dep[x]+dep[y]-2*dep[anc];//cout<<dis<<endl;
        if(dis%2==1){
            printf("0\n");continue;
        }
        if(x==y){
            printf("%d\n",n);continue;
        }
        if(dep[x]==dep[y]){
            int p1=get(x,anc,1),p2=get(y,anc,1);
            printf("%d\n",n-size[p1]-size[p2]);
            continue;
        }
        if(dep[x]<dep[y]) swap(x,y);
        int p1=get(x,x,-dis/2),p2=get(x,p1,1);
        printf("%d\n",size[p1]-size[p2]);
    }
    return 0;
}

原创粉丝点击