codefoeces 671 problem D

D. Roads in Yusland
standard output

Mayor of Yusland just won the lottery and decided to spent money on something good for town. For example, repair all the roads in the town.

Yusland consists of n intersections connected by n - 1 bidirectional roads. One can travel from any intersection to any other intersection using only these roads.

There is only one road repairing company in town, named "RC company". Company's center is located at the intersection 1. RC company doesn't repair roads you tell them. Instead, they have workers at some intersections, who can repair only some specific paths. The i-th worker can be paid ci coins and then he repairs all roads on a path from ui to some vi that lies on the path from ui to intersection 1.

Mayor asks you to choose the cheapest way to hire some subset of workers in order to repair all the roads in Yusland. It's allowed that some roads will be repaired more than once.

If it's impossible to repair all roads print  - 1.

Input

The first line of the input contains two integers n and m (1 ≤ n, m ≤ 300 000) — the number of cities in Yusland and the number of workers respectively.

Then follow n−1 line, each of them contains two integers xi and yi (1 ≤ xi, yi ≤ n) — indices of intersections connected by the i-th road.

Last m lines provide the description of workers, each line containing three integers uivi and ci (1 ≤ ui, vi ≤ n1 ≤ ci ≤ 109). This means that the i-th worker can repair all roads on the path from vi to ui for ci coins. It's guaranteed that vi lies on the path from ui to 1. Note that viand ui may coincide.

Output

If it's impossible to repair all roads then print  - 1. Otherwise print a single integer — minimum cost required to repair all roads using "RC company" workers.

Example
input
6 5
1 2
1 3
3 4
4 5
4 6
2 1 2
3 1 4
4 1 3
5 3 1
6 3 2
output
8
Note

In the first sample, we should choose workers with indices 1, 3, 4 and 5,

some roads will be repaired more than once but it is OK. The cost will be equal to 2 + 3 + 1 + 2 = 8 coins.

————————————————————————————————————

这道题简单来讲就是给你一棵大小为n的树 再给你m条链 每条链有覆盖的范围(只能往上)

也就是u v v一定是u的祖先 链还有代价 求用最小的代价覆盖整颗树 如果无解输出-1

我的写法是一波贪心 从叶子节点开始计算 把从每个点开始的所有的边扔在这个点的平衡树上的

要求长度小的价值一定要小(所以插入的时候记得可以弹掉别的边)

这样之后我们选择的时候每个点我们贪心的选那个最短也就是价值最小的

然后所有的边打一波减的标记(这个可以搞个全局变量) 这样贪心以后用别的边就相当于用别的边

代替现在的这条边 这就保证了答案的正确性

然后我们从叶子节点开始算 如果没有边在他的平衡树里的话就是无解

不然就选一个最小的然后把他剩余的东西扔给他的父亲 这里记得把选的这条边的两端扔在一个并查集里

表示这些点标记过了以后不需要用 然后把自己的边扔给父亲的时候用一波启发式合并 保证复杂度

这样之后总的复杂度就是(nloglog) 

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<set>
#define LL long long
const int M=3e5+7;
int read(){
    int ans=0,f=1,c=getchar();
    while(c<'0'||c>'9'){if(c=='-') f=-1; c=getchar();}
    while(c>='0'&&c<='9'){ans=ans*10+(c-'0'); c=getchar();}
    return ans*f;
}
LL ans;
int n,m;
int f[M];
int find(int x){while(f[x]!=x) x=f[x]=f[f[x]]; return x;}
int first[M],cnt;
struct node{int to,next;}e[2*M];
void ins(int a,int b){e[++cnt]=(node){b,first[a]}; first[a]=cnt;}
void insert(int a,int b){ins(a,b); ins(b,a);}
int deep[M],fa[M];
int dfs(int x,int last){
    for(int i=first[x];i;i=e[i].next){
        int now=e[i].to;
        if(now==last) continue;
        deep[now]=deep[x]+1;
        fa[now]=x;
        dfs(now,x);
    }
}
struct pos{
    int d,w;
    bool operator <(const pos &x)const{return d!=x.d?d>x.d:w>x.w;}
};
std::multiset<pos>tr[M];
typedef std::multiset<pos>::iterator IT;
void delet(int x,pos p,int s){
    p.w+=s;IT it=tr[x].upper_bound(p);
    if(it!=tr[x].begin()){
        it--;
        while(it->w>=p.w){
            if(it==tr[x].begin()){tr[x].erase(it);break;}
            IT now=it; --now;
            tr[x].erase(it);    
            it=now;
        }    
    }
    it=tr[x].upper_bound(p);
    if(it==tr[x].end()||it->w>p.w) tr[x].insert(p);
}
int dec[M];
void push_ans(int x){
    for(int i=first[x];i;i=e[i].next){
        int now=e[i].to;
        if(now==fa[x]) continue;
        push_ans(now);
        if(tr[now].size()>tr[x].size()) tr[x].swap(tr[now]),std::swap(dec[x],dec[now]);
        for(IT it=tr[now].begin();it!=tr[now].end();it++) delet(x,*it,dec[x]-dec[now]);
        tr[now].clear();
    }
    while(tr[x].size()){
        IT it=tr[x].begin();
        if(it->d==deep[x]) tr[x].erase(it);
        else break;
    }
    if(x!=1&&f[x]==x){
        if(tr[x].empty()) puts("-1"),exit(0);
        IT it=tr[x].begin();
        ans+=it->w-dec[x];
        dec[x]=it->w;
        int v=x; while(deep[v]>it->d) v=f[v]=find(fa[v]);
        tr[x].erase(it);
    }
}
int main(){
    int x,y,w;
    n=read(); m=read();
    for(int i=1;i<=n;i++) f[i]=i;
    for(int i=1;i<n;i++) x=read(),y=read(),insert(x,y);
    deep[1]=1; dfs(1,-1);
    for(int i=1;i<=m;i++){
        x=read(); y=read(); w=read();
        pos p=(pos){deep[y],w};
        delet(x,p,0);
    }
    push_ans(1);
    printf("%lld\n",ans);
    return 0;
}
View Code

 

转载于:https://www.cnblogs.com/lyzuikeai/p/7489204.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 题目描述: 定义一个结构体,包含学生的姓名和成绩,输入多个学生的信息,按照成绩从高到低排序输出。 输入格式: 第一行输入一个整数n,表示学生的数量。 接下来n行,每行输入一个字符串和一个整数,表示学生的姓名和成绩。 输出格式: 按照成绩从高到低排序输出每个学生的姓名和成绩,每个学生的姓名和成绩之间用一个空格隔开。 如果有多个学生成绩相同,则按照姓名的字典序从小到大排序。 样例输入: 5 Tom 80 Jerry 90 Bob 80 Alice 85 John 90 样例输出: Jerry 90 John 90 Alice 85 Bob 80 Tom 80 解题思路: 本题需要用到结构体和排序,首先定义一个结构体,包含学生的姓名和成绩,然后输入多个学生的信息,将其存储在结构体数组中,最后按照成绩从高到低排序输出。 排序时需要自定义比较函数,先按照成绩从高到低排序,如果成绩相同,则按照姓名的字典序从小到大排序。 代码实现: ### 回答2: 这道题目要求我们按照学生的成绩从高到低排序,我们可以使用结构体来存储每个学生的信息,包括姓名、学号和成绩。然后我们使用冒泡排序算法来排序,要求按照成绩从高到低排列。 首先,我们需要定义一个结构体来存储学生的信息。假设我们需要存储的三个属性为name, id, score,那么我们可以这样定义结构体: ``` struct Student { char name[20]; char id[20]; int score; }; ``` 然后我们就可以定义一个数组用来存储多个学生的信息: ``` Student students[100]; ``` 接下来,我们需要读入每个学生的信息,存储到这个数组中。假设我们需要读入n个学生的信息,那么我们可以使用循环来读入每个学生的信息: ``` for (int i = 0; i < n; i++) { scanf("%s %s %d", students[i].name, students[i].id, &students[i].score); } ``` 接下来,我们使用冒泡排序算法来排序。对于每一次冒泡,我们将会通过比较相邻的两个元素,如果顺序不对就交换它们的位置。我们需要多次执行这个操作,直到所有元素都按照从大到小的顺序排序完毕。 ``` for (int i = 0; i < n - 1; i++) { for (int j = 0; j < n - i - 1; j++) { if (students[j].score < students[j + 1].score) { Student temp = students[j]; students[j] = students[j + 1]; students[j + 1] = temp; } } } ``` 在最后,我们需要输出排序后的结果。假设我们想要输出每个学生的信息,那么我们可以使用循环来输出: ``` for (int i = 0; i < n; i++) { printf("%s %s %d\n", students[i].name, students[i].id, students[i].score); } ``` 这样就完成了问题d:结构体按成绩排序的实现。 ### 回答3: 这道题的主要任务是将一个包含学生信息的结构体按照成绩从高到低进行排序。我们可以使用冒泡排序或快速排序等算法来实现。 首先我们需要定义一个结构体,包含学生姓名、学号和成绩。 ```c++ struct Student{ string name; string num; int score; }; ``` 接下来,我们定义一个函数,该函数接收一个指向结构体数组的指针,还需要一个整数类型的形参来表示数组的长度,函数的返回值为 void。该函数会根据成绩从高到低排序结构体数组。 ```c++ void sortStudents(Student* arr, int len){ for(int i = 0; i < len - 1; i++){ for(int j = i+1; j < len; j++){ if(arr[i].score < arr[j].score){ Student temp; temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; } } } } ``` 接下来,我们先在主函数中定义一个结构体数组并填充数据。 ```c++ int main(){ Student s[5] = { {"Tom", "001", 85}, {"Lily", "002", 90}, {"Bob", "003", 76}, {"Lucy", "004", 92}, {"John", "005", 88} }; // 调用函数进行排序 sortStudents(s, 5); // 输出排序结果 for(int i = 0; i < 5; i++){ cout << s[i].name << " " << s[i].num << " " << s[i].score << endl; } return 0; } ``` 运行程序后,我们可以看到按照成绩从高到低排序的结果输出。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值