Portal HDU - 3938

原题链接

考察:最小生成树+并查集的运用+离线处理

永远不会动脑思考TAT

看大佬来的思路:

  1. 这道题的询问量很大.因此可以采取一些技巧.我们可以发现L大的答案是可以由L小的答案累加得来的.因此这道题对询问进行排序.先处理L小的询问.再进行累加推导L大的询问.
  2. 当i,j有多种路径,我们是选择一条经过路径带权值最大值里最小的.也就是说为了让i,j连通.我们必须选择权值小的边使得他们连通.这里可以可以考虑最小生成树的算法
  3. 综上所述,我们需要对询问与路径进行排序.当两点不在一个集合里时,说明这两条边的答案没有算过.经过这条边的答案为sz[i]*sz[j].这里是排列组合
  4. 如果两点已经在集合里,那么就说明经过这两点的答案前面已经算过了
 1 #include <iostream>
 2 #include <cstdio>
 3 #include <algorithm>
 4 using namespace std;
 5 const int N = 10010,M = 50010;
 6 int p[N],n,m,q,sz[N];
 7 struct Edge{
 8     int u,v,w;
 9     bool operator<(const Edge& x)const{
10         return this->w<x.w;
11     }
12 }edge[M]; 
13 struct Query{
14     int id,ans,w;
15     bool operator<(const Query& x)const{
16         return this->w<x.w;
17     }
18 }query[N];
19 struct cmp{
20     bool operator()(Query q1,Query q2){
21         return q1.id<q2.id;
22     }
23 };
24 int findf(int x)
25 {
26     if(x!=p[x]) 
27     {
28         int t = findf(p[x]);
29         sz[x]+=sz[p[x]];
30         p[x] = t;
31     }
32     return p[x];
33 }
34 int main()
35 {
36 //    freopen("in.txt","r",stdin);
37     while(scanf("%d%d%d",&n,&m,&q)!=EOF)
38     {
39         int cnt = 1; fill(sz,sz+N,1);
40         for(int i=1;i<=n;i++) p[i] = i;
41         for(int i=1;i<=m;i++)
42            scanf("%d%d%d",&edge[i].u,&edge[i].v,&edge[i].w);
43         for(int i=1;i<=q;i++) {
44             int s;
45             scanf("%d",&s); 
46             query[i] = {i,0,s};
47         } 
48         sort(edge+1,edge+m+1);
49         sort(query+1,query+q+1);
50         for(int i=1;i<=q;i++)//从小到大处理查询.大的答案是由小的答案推出来的 
51         {
52             while(query[i].w>=edge[cnt].w)
53             {
54                 int u = findf(edge[cnt].u),v = findf(edge[cnt].v);
55                 cnt++;
56                 if(u==v) continue;
57                 p[u] = v;
58                 query[i].ans += sz[u]*sz[v];
59                 sz[v]+=sz[u];
60             }
61             query[i].ans += query[i-1].ans;
62         }
63         sort(query+1,query+q+1,cmp());
64         for(int i=1;i<=q;i++)
65             printf("%d\n",query[i].ans);
66     }
67     return 0;
68 }

 

posted @ 2021-01-14 16:41  acmloser  阅读(92)  评论(0编辑  收藏  举报