P6111 [USACO18JAN]MooTube S
输出格式
输出 Q 行。在第 i 行,输出 FJ 的第 i 个问题的答案。
输入输出样例
输入
4 3
1 2 3
2 3 2
2 4 4
1 2
4 1
3 1
输出
3
0
2
思路:
如果题目K只有一个值,然后求每个点的推荐的视频数,那就简单了。
但是难在K是个变量,就在要抓破头皮时,发现了洛谷竟然有题解。
一开始对于每一对点,我想将这两个点之间所连的边的权值大于等于K都加进去。但还是老问题,K是个变量!
我们先将问题按K值排序(降),再按边权值将每条边进行排序(降)
因为对于一条边,如果K值大的你都能满足,那么小的也可以,换言之:你不会影响后面的结果,有点像动态规划的无后效性。
接下来,其实就是个加边的问题了。
根据题意,不能自荐,所以答案要-1(-他本身)。
#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#include<string>
#include<algorithm>
#define fre(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout);
using namespace std;
const int MAX=2147483647;
const int N=5e3+10;
int n,qu,f[N],num[N],ans[N];
struct node
{
int u,v,w;
}edge[N];
struct node1
{
int id,k,v;
}q[N];
int find(int x) {return x==f[x]?x:f[x]=find(f[x]);}
void unionn(int x,int y)
{
int a=find(x),b=find(y);
if(a!=b) f[a]=b,num[b]+=num[a]; //num[i]为父节点i所连满足条件的边数
}
bool cmp1(node x,node y){return x.w>y.w;}
bool cmp2(node1 x,node1 y){return x.k>y.k;}
void input()
{
scanf("%d%d",&n,&qu);
for(int i=1;i<=n;i++) f[i]=i,num[i]=1;
for(int i=1;i<n;i++) scanf("%d%d%d",&edge[i].u,&edge[i].v,&edge[i].w);
for(int i=1;i<=qu;i++) scanf("%d%d",&q[i].k,&q[i].v),q[i].id=i;
}
void work()
{
sort(edge+1,edge+n,cmp1);
sort(q+1,q+qu+1,cmp2);
int j=1;
for(int i=1;i<=qu;i++)
{
while(edge[j].w>=q[i].k&&j<n) unionn(edge[j].u,edge[j].v),j++;
ans[q[i].id]=num[find(q[i].v)]-1;
//这里不要写成num[q[i].v],你是在个集合里面,所以要找集合中的老大才知道有多少成员
}
for(int i=1;i<=qu;i++) printf("%d\n",ans[i]);
}
int main()
{
//fre();
input();
work();
return 0;
}