codefoeces problem 671D——贪心+启发式合并+平衡树

D. Roads in Yusland

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?≤?n, 1?≤?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 vi and 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 51 21 33 44 54 62 1 23 1 44 1 35 3 16 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.

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

#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();
    }
    //if(x==2) for(IT it=tr[x].begin();it!=tr[x].end();it++) printf("A[%d %d]\n",it->d,it->w);
    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;
}

时间: 2024-10-15 14:11:02

codefoeces problem 671D——贪心+启发式合并+平衡树的相关文章

BZOJ 2809 APIO 2012 dispatching 平衡树启发式合并

题目大意:给出一棵树,每一个节点有两个值,分别是这个忍者的薪水和忍者的领导力.客户的满意程度是这个点的领导力乘能够取得人数,前提是取的人的薪水总和不超过总的钱数. 思路:只能在子树中操作,贪心的想,我们只要这个子树中cost最小的那些点就可以了.所以就深搜一次,每到一个节点上,把自己和所有子节点的平衡树启发式和并,然后保留不超过总钱数的人数,统计.数据范围比较大,能开long long的地方不要吝啬. PS:吐槽一下,一开始这个题一直TTT,我以为是我常数写的太大了,别人都用左偏堆写,是不是平衡

【pb_ds】【平衡树启发式合并】【并查集】bzoj2733 [HNOI2012]永无乡

用并查集维护联通性.对每个联通块维护一个平衡树.合并时启发式合并.比较懒,用了pb_ds. 1 #include<cstdio> 2 #include<ext/pb_ds/assoc_container.hpp> 3 #include<ext/pb_ds/tree_policy.hpp> 4 using namespace std; 5 using namespace __gnu_cxx; 6 using namespace __gnu_pbds; 7 tree<

hdu 6133---Army Formations(启发式合并+树状数组)

题目链接 Problem Description > Stormtroopers were the assault/policing troops of the Galactic Empire. Dissenting citizens referred to them as bucketheads, a derogatory nickname inspired by the bucket-shaped helmets of stormtroopers. They wore white armor

BZOJ 2809 APIO2012 dispatching Treap+启发式合并 / 可并堆

题目大意:给定一棵树,选定一棵子树中的一些点,薪水和不能超过m,求点的数量*子树根节点的领导能力的最大值 考虑对于每个节点,我们维护一种数据结构,在其中贪心寻找薪金小的雇佣. 每个节点暴力重建一定不行,我们考虑可并数据结构,每个节点将子节点的信息直接合并即可 可以用启发式合并的Treap,也可以用可并堆 今天特意去学了这玩应0.0 先写了左偏树 然后又写了下随机堆-- 后者速度上更快一些 不过建议从左偏树开始学起 总之平衡树常数各种大就是了0.0 Treap+启发式合并 #include<cst

启发式合并(堆、set、splay、treap)/线段树合并学习小记

启发式合并 刚听到这个东西的时候,我是相当蒙圈的.特别是"启发式"这三个字莫名的装逼,因此之前一直没有学. 实际上,这个东西就是一个SB贪心. 以堆为例,若我们要合并两个堆a.b,我们有一种极其简单的做法:那就是比较一下它们的大小,将小的堆的每个元素依次插入到大的堆中.不妨设\(|a|≤|b|\),则时间复杂度即为:\(O(|a|*log_2(|a|+|b|))\). 这个东西看似很慢,但当点数较小的时候,我们可以证明复杂度是可被接受的. 比如我们要合并n个堆,这n个堆共有m个点.设这

【BZOJ2733】永无乡[splay启发式合并or线段树合并]

题目大意:给你一些点,修改是在在两个点之间连一条无向边,查询时求某个点能走到的点中重要度第k大的点.题目中给定的是每个节点的排名,所以实际上是求第k小:题目求的是编号,不是重要度的排名.我一开始差点被这坑了. 网址:http://www.lydsy.com/JudgeOnline/problem.php?id=2733 这道题似乎挺经典的(至少我看许多神犇很早就做了这道题).这道题有两种写法:并查集+(splay启发式合并or线段树合并).我写的是线段树合并,因为--splay不会打+懒得学.

[BZOJ 1483][HNOI 2009]梦幻补丁(有序表启发式合并)

题目:http://www.lydsy.com:808/JudgeOnline/problem.php?id=1483 分析: 先将不同的颜色的出现位置从小到大用几条链表串起来,然后统计一下答案 对于每次修改,修改一下答案即可,修改之后需要将两个颜色的链表合并就行了,但感觉似乎会TLE? 以下摘录与Hzwer的blog: 1:将两个队列合并,有若干队列,总长度为n,直接合并,最坏O(N), 2:启发式合并呢? 每次我们把短的合并到长的上面去,O(短的长度) 咋看之下没有多大区别, 下面让我们看看

BZOJ 2733 [HNOI2012]永无乡(启发式合并+Treap+并查集)

[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=2733 [题目大意] 给出n个点,每个点都有自己的重要度,现在有连边操作和查询操作, 查询操作要求找出一个连通块中重要度第k的点的id [题解] 我们用Treap维护每个连通块,对于连边操作,我们用启发式合并, 将size比较小的Treap并入size比较大的Treap,同时用并查集维护连通信息 [代码] #include <cstdio> #include <algorith

Bzoj 2733: [HNOI2012]永无乡 数组Splay+启发式合并

2733: [HNOI2012]永无乡 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 3955  Solved: 2112[Submit][Status][Discuss] Description 永无乡包含 n 座岛,编号从 1 到 n,每座岛都有自己的独一无二的重要度,按照重要度可 以将这 n 座岛排名,名次用 1 到 n 来表示.某些岛之间由巨大的桥连接,通过桥可以从一个岛 到达另一个岛.如果从岛 a 出发经过若干座(含 0 座)桥可以到达