EOJ二月月赛补题

A:昔我往矣

lca+dfs序,先做出所有点的dfs序,然后对于每一个询问,以dfs序最小和最大的为两个端点,然后往里面加点相当于加上一条分叉出去的链,用LCA求解即可。

下附代码:

  1 #include<bits/stdc++.h>
  2 #define ll long long
  3 using namespace std;
  4 const ll INF=0X3f3f3f3f3f3f3f3f;
  5 int Next[100005],to[100005];
  6 ll len[100005];
  7 int head[50005];
  8 ll tot=0;
  9 int dep[50005],f[50005][20];
 10 ll l[50005][20],n,q;
 11 int a[10];
 12 int dfn[50005],cnt;
 13 struct node{
 14     ll p,l;
 15 };
 16 bool cmp(int x,int y){
 17     return dfn[x]<dfn[y];
 18 }
 19 inline void add(int a,int b,ll c){
 20     Next[tot]=head[a],to[tot]=b,len[tot]=c;
 21     head[a]=tot++;
 22 }
 23 inline void deal(ll x,ll fa){
 24     dep[x]=dep[fa]+1;
 25     for (int i=0; i<=16; i++){
 26         f[x][i+1]=f[f[x][i]][i];
 27         l[x][i+1]=l[x][i]+l[f[x][i]][i];
 28     }
 29     for (int i=head[x]; i!=-1; i=Next[i]){
 30         int y=to[i];
 31         if (y==fa) continue;
 32         f[y][0]=x;
 33         l[y][0]=len[i];
 34         deal(y,x);
 35     }
 36 }
 37 void dfs(int x,int pre){
 38     if (dfn[x]!=0) return;
 39     dfn[x]=++cnt;
 40     for (int i=head[x]; i!=-1; i=Next[i]){
 41         int y=to[i];
 42         if (y!=pre){
 43             dfs(y,x);
 44         }
 45     }
 46 }
 47 inline node lca(int x,int y){
 48     int tmp=x;
 49     ll ret=0;
 50     if (dep[x]<dep[y]) swap(x,y);
 51     for (int i=16; i>=0; i--){
 52         if (dep[f[x][i]]>=dep[y])  {
 53             ret+=l[x][i];
 54             x=f[x][i];
 55         }
 56         if (x==y) {
 57             return {y,ret};
 58         }
 59     }
 60     for (int i=16; i>=0; i--){
 61         if (f[x][i]!=f[y][i]){
 62             ret=ret+l[x][i];
 63             ret=ret+l[y][i];
 64             x=f[x][i];
 65             y=f[y][i];
 66         }
 67     }
 68     ret+=l[x][0]+l[y][0];
 69     return {f[x][0],ret};
 70 }
 71 int main(){
 72     scanf("%lld",&n);
 73     for (int i=0; i<n; i++){
 74         head[i]=-1;
 75     }
 76     for (int i=1; i<n; i++){
 77         ll a,b,c;
 78         scanf("%lld%lld%lld",&a,&b,&c);
 79         add(a,b,c);
 80         add(b,a,c);
 81     }
 82     deal(0,-1);
 83     scanf("%lld",&q);
 84     cnt=0;
 85     dfs(0,-1);
 86     while (q--){
 87         for (int i=1; i<=5; i++){
 88             scanf("%lld",&a[i]);
 89         }
 90         sort(a+1,a+6,cmp);
 91         node p=lca(a[1],a[5]);
 92         ll res=p.l;
 93         vector<int> now;
 94         now.push_back(a[1]);
 95         now.push_back(a[5]);
 96         for (int i=2; i<=4; i++){
 97             int maxn=0,pp=0;
 98             for (auto j:now){
 99                 node p1=lca(a[i],j);
100                 if (dep[p1.p]>maxn){
101                     maxn=dep[p1.p];
102                     pp=p1.p;
103                 }
104             }
105             res+=lca(pp,a[i]).l;
106             now.push_back(a[i]);
107         }
108         printf("%lld\n",res);
109     }
110     return 0;
111 }
View Code

 

B:杨柳依依

对于每组起点终点,bfs求出每个点到他们的最短距离与最短路种数

那么对于每组起点终点,如果一个点到起点终点的最短路之和与起点终点距离相同,说明该点在最短路上,概率加上 起点开始的种数*终点开始的种数/总的最短路种数

下附代码:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int INF=0X3f3f3f3f;
 4 int n,m;
 5 int head[5005],Next[80005],to[80005],tot=0;
 6 double E[5005];
 7 int cnt[2][5005],d[2][5005],b[5005],q[5005];
 8 void add(int a,int b){
 9     Next[tot]=head[a],to[tot]=b;
10     head[a]=tot++;
11 }
12 void bfs(int s,int cnt[],int d[]){
13     memset(b,0,sizeof(b));
14         d[s]=0,cnt[s]=1;
15         int r=1,l=0;
16         q[r]=s;
17         while (l<=r){
18             int x=q[++l];
19             if (b[x]) continue;
20             b[x]=1;
21             for (int i=head[x]; i!=-1; i=Next[i]){
22                 int y=to[i];
23                 if (d[y]>d[x]+1){
24                     d[y]=d[x]+1;
25                     cnt[y]=cnt[x];
26                         q[++r]=y;
27                 }
28                 else if (d[y]==d[x]+1){
29                     cnt[y]+=cnt[x];
30                 }
31             }
32         }
33 }
34 int main(){
35     scanf("%d%d",&n,&m);
36     for (int i=0; i<n; i++) head[i]=-1;
37     for (int i=1; i<=m; i++){
38         int x,y;
39         scanf("%d%d",&x,&y);
40         add(x,y);
41         add(y,x);
42     }
43     int T;
44     scanf("%d",&T);
45     while (T--){
46         int st,ed;
47         scanf("%d%d",&st,&ed);
48         memset(cnt,0,sizeof(cnt));
49         memset(d,INF,sizeof(d));
50         bfs(st,cnt[0],d[0]);
51         bfs(ed,cnt[1],d[1]);
52         if (d[0][ed]==INF) continue;
53         for (int i=0; i<n; i++){
54             if (d[0][i]+d[1][i]==d[0][ed]){
55                 E[i]+=1.0*cnt[0][i]*cnt[1][i]/cnt[0][ed];
56             }
57         }
58     }
59     double maxn=-INF;
60     int pos;
61     for (int i=0; i<n; i++){
62         if (E[i]>maxn){
63             maxn=E[i];
64             pos=i;
65         }
66     }
67     printf("%d\n",pos);
68 }
View Code

 

posted @ 2021-02-13 15:27  我是菜狗QAQ  阅读(90)  评论(0编辑  收藏  举报