•参考资料
•题意
给出一棵树,根节点为1。
每条边有一个权值,树上有红色结点 m 个,其花费为 0 ,其余为黑色;
每个黑色结点的花费为其到最近红色祖先的经过的路径权值之和。
有 q 次询问,每次给出一个点集;
问将树上任意一个结点涂成红色结点后,点集中所有点的花费的最大值的最小是多少。
•题解
相关变量解释:
sum : 每次询问中询问的点集个数
a[ ] : 存储每次询问到的点集
costR[i] : 结点 i 距其最近红色祖先的花费
预处理每个点到根的距离cost、到最近红色祖先的距离 costR 和 ST 表。
对于每次询问,将a[ ] 按 costR 从大到小排序,在 0~costR[a[0]] 范围内二分答案;
对所有大于答案的点求它们的公共祖先(利用ST表可以O(1)求两点的公共祖先),将其涂红;
之后计算每个大于答案的点的新花费是否小于答案。
•Code
View Code1 #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 }