(离线处理+并查集) hdu 3938

Portal

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 977    Accepted Submission(s): 490

Problem Description

ZLGG found a magic theory that the bigger banana the bigger banana peel .This important theory can help him make a portal in our universal. Unfortunately, making a pair of portals will cost min{T} energies. T in a path between point V and point U is the length of the longest edge in the path. There may be lots of paths between two points. Now ZLGG owned L energies and he want to know how many kind of path he could make.

Input

There are multiple test cases. The first line of input contains three integer N, M and Q (1 < N ≤ 10,000, 0 < M ≤ 50,000, 0 < Q ≤ 10,000). N is the number of points, M is the number of edges and Q is the number of queries. Each of the next M lines contains three integers a, b, and c (1 ≤ a, b ≤ N, 0 ≤ c ≤ 10^8) describing an edge connecting the point a and b with cost c. Each of the following Q lines contain a single integer L (0 ≤ L ≤ 10^8).

Output

Output the answer to each query on a separate line.

Sample Input

10 10 10
7 2 1
6 8 3
4 5 8
5 8 2
2 8 9
6 4 5
2 1 5
8 10 5
7 3 7
7 8 8
10
6
1
5
9
1
8
2
7
6

Sample Output

36
13
1
13
36
1
36
2
16
13

这题挺不错的,学到了离线算法。题目要求两点之间最大边的最小值小于某值的个数。其实就是求点对。

集合划分

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<string>
#include<algorithm>
#include<cstdlib>
using namespace std;
int n,m,q,set[50010],num[50010],ans[50010];
struct node
{
      int x,y,w;
}e[50010];
struct nod
{
      int x,id;
}aa[50010];
bool cmp(node a,node b)
{
      return a.w<b.w;
}
bool cmp1(nod a,nod b)
{
      return a.x<b.x;
}
int find(int x)
{
      if(x!=set[x])
            set[x]=find(set[x]);
      return set[x];
}
int Union(int a,int b)
{
      int fx,fy;
      fx=find(a),fy=find(b);
      if(fx==fy) return 0;
      int t=num[fx]*num[fy];
      num[fx]+=num[fy];
      num[fy]=0;
      set[fy]=fx;
      return t;
}
int main()
{
      while(scanf("%d%d%d",&n,&m,&q)!=EOF)
      {
           memset(e,0,sizeof(e));
           memset(ans,0,sizeof(ans));
           for(int i=1;i<=n;i++)
                  set[i]=i,num[i]=1;
           for(int i=1;i<=m;i++)
           {
                 scanf("%d%d%d",&e[i].x,&e[i].y,&e[i].w);
           }
           sort(e+1,e+1+m,cmp);
           for(int i=1;i<=q;i++)
           {
                 scanf("%d",&aa[i].x);
                 aa[i].id=i;
           }
           sort(aa+1,aa+1+q,cmp1);
           int k=1,cnt=0;
           for(int i=1;i<=q;i++)
           {
                 while(k<=m&&e[k].w<=aa[i].x)
                 {
                       cnt+=Union(e[k].x,e[k].y);
                       k++;
                 }
                 ans[aa[i].id]=cnt;
           }
           for(int i=1;i<=q;i++)
                  printf("%d\n",ans[i]);
      }
      return 0;
}

  

时间: 2024-11-25 18:18:18

(离线处理+并查集) hdu 3938的相关文章

集合问题 离线+并查集 HDU 3938

题目大意:给你n个点,m条边,q个询问,每条边有一个val,每次询问也询问一个val,定义:这样条件的两个点(u,v),使得u->v的的价值就是所有的通路中的的最长的边最短.问满足这样的点对有几个. 思路:我们先将询问和边全部都按照val排序,然后我们知道,并查集是可以用来划分集合的,所以我们就用并查集来维护每一个集合就行了. //看看会不会爆int!数组会不会少了一维! //取物问题一定要小心先手胜利的条件 #include <bits/stdc++.h> using namespac

URAL1671 Anansi&#39;s Cobweb(离线做 + 并查集)

传送门 大意:给出一个无向图,删除Q条边,每删除一次就询问一次目前的连通块的数目. 思路:离线搞, 把删边转换为加边,每加一次边,若两个顶点不连通就用并查集把着这两个连通块合并. 代码: #include<cstdio> #include<cstring> #include<algorithm> #define MAXN 100005 using namespace std; int n, m, q; int s[MAXN], t[MAXN]; int ban[MAXN

【bzoj4551】[Tjoi2016&amp;Heoi2016]树 离线处理+并查集

题目描述 在2016年,佳媛姐姐刚刚学习了树,非常开心.现在他想解决这样一个问题:给定一颗有根树(根为1),有以下两种操作:1. 标记操作:对某个结点打上标记(在最开始,只有结点1有标记,其他结点均无标记,而且对于某个结点,可以打多次标记.)2. 询问操作:询问某个结点最近的一个打了标记的祖先(这个结点本身也算自己的祖先)你能帮帮他吗? 输入 输入第一行两个正整数N和Q分别表示节点个数和操作次数接下来N-1行,每行两个正整数u,v(1≤u,v≤n)表示u到v有一条有向边接下来Q行,形如"oper

【bzoj5183】[Baltic2016]Park 离线+对偶图+并查集

题目描述 在Byteland的首都,有一个矩形围栏围起来的公园.在这个公园里树和访客都以一个圆形表示.公园有四个出入口,每个角落一个(1=左下角,2=右下角,3=右上角,4=左上角).访客能通过这些出入口进出公园.访客在同时碰到一个角落的两条边时就可以通过该角落进出公园.访客在公园里可以自由地移动,但他们不能和树和围栏相交.对于每个访客,给定他们进入公园的出入口,你的任务是计算他们能在哪个出入口离开公园. 输入 输入的第一行包含两个整数:n,m:树的数量和访客的数量. 第二行包含两个整数:w,h

HDU 5441 离线处理 + 并查集

题意:给n个节点m条带权值边的无向图.然后q个问题,每次询问点对的数目,点对需要满足的条件是:1)连通:2)其路径的最大权值不能超过询问值. 分析:如果没次询问一次,dfs一次,很可能超时,因此可以用并查集.离线处理,把边按权值排序,把问题按大小排序.然后离线的过程就是不断向图中加边的过程. 比如样例如下: 然后离线处理,排完序后将会是一条一条的加边:问题也排了序,因此是个累加过程... 1 #include <cstdio> 2 #include <iostream> 3 #in

【FZU】Problem 2059 MM(离线处理并查集)

离线处理,并查集 #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int maxn = 100005; struct Node{ int id,value; }node[maxn],input[maxn]; bool cmp(Node p,Node q){ return p.value > q.value; } int p[maxn],vis[max

hdu3938 Portal 离线的并查集

离线算法是将全部输入都读入,计算出所有的答案以后再输出的方法.主要是为避免重复计算.类似于计算斐波那契数列的时候用打表的方法. 题目:给一个无向图,求有多少个点对,使得两点间的路径上的花费小于L,这里路径上的花费是这样规定的,a.b两点之间所有的路径中的最大边的最小值.    当然题目上不是这么写的.它问的是有多少种路径,这里就比较模糊了,到底两个路径怎样才算是两种路径呢,这时候重新看题,可以发现,如果理解为路径中经过的点不同的话,题目中给的所谓两点间的花费这个定义就没有意义了,所以就可以猜测,

并查集 -- HDU 1232 UVALA 3644

并查集: 1 int pa[maxn],Rank[maxn]; 2 ///初始化 x 集合 3 void make_set(int x) 4 { 5 pa[x]=x; 6 Rank[x]=0; 7 } 8 ///递归查找 x 所在的集合 9 int find_set(int x) 10 { 11 if(pa[x]!=x) pa[x]=find_set(pa[x]); 12 return pa[x]; 13 } 14 ///更新根节点,如果不更新可能会暴栈 15 void mix(int x,in

[hdu4585]离线,并查集

题意:把一些数加到集合里面,每个数有两个属性,分别是编号和值,加进去之前询问集合里面距离自己“最近”的数的编号.最近的意思是值的差的绝对值最小,如果有相等的,则取值小的.并且已知所有数的id和value都是唯一的. 思路:把处理过程反过来,就变成了一次把一个点删除,删除可以用数组标记,而询问则转化为找某个数左边的第一个没标记的数和右边的第一个没被标记的数,由于删除是永久的,所以完全可以通过并查集来加速,标记也可以省略. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16