传送门

 

•参考资料

  [1]:ACM-ICPC 2018 青岛赛区网络预赛 B. Red Black Tree (LCA、二分)

•题意 

  给出一棵树,根节点为1。

  每条边有一个权值,树上有红色结点 m 个,其花费为 0 ,其余为黑色;

  每个黑色结点的花费为其到最近红色祖先的经过的路径权值之和。

  有 q 次询问,每次给出一个点集;

  问将树上任意一个结点涂成红色结点后,点集中所有点的花费的最大值的最小是多少。

•题解

  相关变量解释:

    sum : 每次询问中询问的点集个数

    a[  ]  : 存储每次询问到的点集

    costR[i] : 结点 i 距其最近红色祖先的花费

  预处理每个点到根的距离cost、到最近红色祖先的距离 costR 和 ST 表。

  对于每次询问,将a[ ] 按 costR 从大到小排序,在 0~costR[a[0]] 范围内二分答案;

  对所有大于答案的点求它们的公共祖先(利用ST表可以O(1)求两点的公共祖先),将其涂红;

  之后计算每个大于答案的点的新花费是否小于答案。

•Code

  1 #include<iostream>
  2 #include<vector>
  3 #include<cstdio>
  4 #include<cmath>
  5 #include<algorithm>
  6 #include<cstring>
  7 using namespace std;
  8 #define pb push_back
  9 #define ll long long
 10 #define mem(a,b) (memset(a,b,sizeof a))
 11 const int maxn=1e5+50;
 12 
 13 int n,m,q;
 14 //===============Restore Graph============
 15 struct Node
 16 {
 17     int to;
 18     ll w;
 19     Node(int to,int w):to(to),w(w){}
 20 };
 21 vector<Node >G[maxn];
 22 void addEdge(int u,int v,int w)
 23 {
 24     G[u].pb(Node(v,w));
 25     G[v].pb(Node(u,w));
 26 }
 27 //=========================================
 28 int vs[2*maxn];//欧拉序列,范围区间为 [1,total]
 29 int depth[2*maxn];//欧拉序列对应的深度序列
 30 int pos[maxn];//pos[i] : 结点 i 再欧拉序列中第一次出现的位置
 31 ll cost[maxn];//cost[i] : 结点 i 距根据点的距离
 32 ll costR[maxn];//costR[i] : 结点 i 距最近红色祖先结点的距离,初始化为 -1
 33 int total;//欧拉序列的大小
 34 void dfs(int u,int f,int dep,ll dis)
 35 {
 36     vs[++total]=u;
 37     depth[total]=dep;
 38     pos[u]=total;
 39     cost[u]=dis;
 40     for(int i=0;i < G[u].size();++i)
 41     {
 42         Node e=G[u][i];
 43         if (e.to == f)
 44             continue;
 45         costR[e.to]=(costR[e.to] == 0 ? 0:costR[u]+e.w);
 46         dfs(e.to,u,dep+1,dis+e.w);
 47         vs[++total]=u;
 48         depth[total]=dep;
 49     }
 50 }
 51 //==================RMQ======================
 52 struct Node2
 53 {
 54     int mm[2 * maxn];
 55     int dp[2 * maxn][20];
 56     void ST()
 57     {
 58         int n=total;
 59         mm[0] = -1;
 60         for (int i = 1; i <= n; i++)
 61         {
 62             mm[i]=((i&(i-1))==0) ? mm[i - 1] + 1:mm[i - 1];
 63             dp[i][0]=i;
 64         }
 65         for (int j=1;j <= mm[n];j++)
 66             for (int i=1;i+(1<<j)-1 <= n;i++)
 67                 if(depth[dp[i][j - 1]] < depth[dp[i+(1<<(j-1))][j-1]])
 68                     dp[i][j]=dp[i][j-1];
 69                 else
 70                     dp[i][j]=dp[i+(1<<(j-1))][j-1];
 71     }
 72     int Lca(int u, int v)
 73     {
 74         u=pos[u],v=pos[v];
 75         if (u > v)
 76             swap(u, v);
 77         int k = mm[v-u+1];
 78         if(depth[dp[u][k]] <= depth[dp[v-(1<<k)+1][k]])
 79             return vs[dp[u][k]];
 80         return vs[dp[v-(1<<k)+1][k]];
 81     }
 82 }_rmq;
 83 //==========================================
 84 int a[maxn];
 85 int sum;
 86 bool cmp(int a, int b)
 87 {
 88     return costR[a] > costR[b];
 89 }
 90 bool Check(ll x)
 91 {
 92     if(costR[a[0]] <= x)
 93         return true;
 94     int lca=a[0];
 95     for(int i=1;i < sum;i++)
 96     {
 97         if(costR[a[i]] <= x)
 98             break;
 99         lca=_rmq.Lca(lca,a[i]);
100     }
101     for(int i = 0;i < sum;i++)
102     {
103         if(costR[a[i]] <= x)
104             return true;
105         if(cost[a[i]]-cost[lca] > x)
106             return false;
107     }
108     return true;
109 }
110 void Solve()
111 {
112     dfs(1,-1,0,0);
113     _rmq.ST();
114     while(q--)
115     {
116         scanf("%d",&sum);
117         for (int i=0;i < sum; i++)
118             scanf("%d",&a[i]);
119         sort(a,a+sum,cmp);
120         ll l=0,r=costR[a[0]];
121         while(l < r)
122         {
123             ll mid=(l+r)/2;
124             if(Check(mid))
125                 r=mid;
126             else
127                 l=mid + 1;
128         }
129         printf("%lld\n",l);
130     }
131 }
132 void init()
133 {
134     mem(costR,-1);
135     total=0;
136     for(int i=0;i < maxn;++i)
137         G[i].clear();
138 }
139 int main()
140 {
141     int t;
142     scanf("%d", &t);
143     while(t--)
144     {
145         init();
146         scanf("%d%d%d",&n,&m,&q);
147         while(m--)
148         {
149             int red;
150             scanf("%d",&red);
151             costR[red]=0;
152         }
153         costR[1]=0;
154         for(int i=1;i<n;i++)
155         {
156             int u,v,w;
157             scanf("%d%d%d",&u,&v,&w);
158             addEdge(u,v,w);
159         }
160         Solve();
161     }
162     return 0;
163 }
View Code

相关文章:

  • 2022-01-29
  • 2022-12-23
  • 2022-12-23
  • 2022-02-13
  • 2022-01-05
  • 2021-12-19
  • 2022-12-23
猜你喜欢
  • 2022-12-23
  • 2022-12-23
  • 2021-09-09
  • 2021-11-30
  • 2022-02-01
  • 2021-11-05
  • 2021-08-30
相关资源
相似解决方案