Hihocoder1883 : 生成树问题(并查集+树剖+线段树)
描述
有一个无向图,有n个点,m1条第一类边和m2条第二类边。第一类边有边权,第二类边无边权。请为第二类的每条边定义一个边权,使得第二类边可能全部出现在该无向图的最小生成树上,同时要求第二类边的边权总和尽可能大。
注:第二类边不会形成环
输入
第一行三个数n,m2,m1
接下来m2行,每行两个数,描述一条第二类边,分别表示两个端点接下来m1行,每行三个数,描述一条第一类边,分别表示两个端点和边权
对于30%的数据,n ≤ 5
对于60%的数据,n ≤ 1000
对于100%的数据,1 ≤ n ≤ 100000, m1 ≤ 2 × n, m2 < n
输出
输出一个数,表示第二类边的权值总和最大可能为多少。(若可能为无穷大则输出-1)
- 样例输入
-
5 2 3
1 2
4 5
2 3 100
3 4 100
1 5 1000 - 样例输出
-
2000
思路:我们先把第二类(B)和第一类(A)按权值排序,生成一个最小生成树,那么,对于第一类里面的那些没有被加入到树里的边e,我们需要保证这些边的两端在树上的路径e.u->e.v上的所有A类边都不大于e.cost。
所以我们需要去更新A类边的权值,我们把A类边都的权值都设为inf,然后用e.cost去更新,更新的过程就是势能线段树,如果区间有inf,那么就更新,否则跳过这个区间,因为每个A类边最多被跟新一次,势能会变小,这样可以保证复杂度。
(开始一直在想持久化并查集或者LCT...赶脚做不出来,然后才写了这个又长又臭的代码。求更简单的方法。qwq
(补充,好像不用线段树啊,直接用并查集找祖先里第一个A类边即可...
#include<bits/stdc++.h>
#define ll long long
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
const int maxn=;
const int inf=1e9;
int x[maxn],y[maxn],Laxt[maxn],Next[maxn],To[maxn],Len[maxn];
int fa[maxn],Mx[maxn],tot,N,cnt,dep[maxn];
int a[maxn],sz[maxn],son[maxn],Top[maxn],p[maxn],q[maxn];
struct in{ int u,v,cost; }s[maxn];
bool cmp(in p,in q){ return p.cost<q.cost;}
int ff[maxn]; int find(int x){if(x==ff[x]) return x; return ff[x]=find(ff[x]);}
void add(int u,int v,int c){
Next[++cnt]=Laxt[u]; Laxt[u]=cnt; To[cnt]=v; Len[cnt]=c;
}
void dfs1(int u,int f){
dep[u]=dep[f]+; fa[u]=f; sz[u]=;
for(int i=Laxt[u];i;i=Next[i])
if(To[i]!=f) {
dfs1(To[i],u),sz[u]+=sz[To[i]];
a[To[i]]=Len[i];
if(sz[To[i]]>sz[son[u]]) son[u]=To[i];
}
}
void dfs2(int u,int top)
{
Top[u]=top; p[++tot]=u; q[u]=tot;
if(son[u]) dfs2(son[u],top);
for(int i=Laxt[u];i;i=Next[i]){
if(To[i]!=son[u]&&dep[To[i]]>dep[u])
dfs2(To[i],To[i]);
}
}
void build(int Now,int L,int R)
{
if(L==R) { Mx[Now]=a[p[L]]; return ;}
int Mid=(L+R)>>;
build(Now<<,L,Mid); build(Now<<|,Mid+,R);
Mx[Now]=max(Mx[Now<<],Mx[Now<<|]);
}
int query(int Now,int L,int R,int l,int r)
{
if(Mx[Now]<inf) return ;
if(L==R){Mx[Now]=; return ;}
int Mid=(L+R)>>,res=;
if(l<=Mid) res+=query(Now<<,L,Mid,l,r);
if(r>Mid) res+=query(Now<<|,Mid+,R,l,r);
Mx[Now]=max(Mx[Now<<],Mx[Now<<|]);
return res;
}
int Query(int u,int v)
{
int f1=Top[u],f2=Top[v],res=;
while(f1!=f2){
if(dep[f1]<dep[f2]) swap(f1,f2),swap(u,v);
res+=query(,,N,q[f1],q[u]);
u=fa[f1]; f1=Top[u];
}
if(u!=v){
if(dep[u]>dep[v]) swap(u,v);
res+=query(,,N,q[son[u]],q[v]);
}
return res;
}
int main()
{
int A,B; ll ans=;
scanf("%d%d%d",&N,&A,&B);
rep(i,,N) ff[i]=i;
rep(i,,A){
scanf("%d%d",&x[i],&y[i]);
int fu=find(x[i]),fv=find(y[i]);
ff[fu]=fv;
add(x[i],y[i],inf); add(y[i],x[i],inf);
}
rep(i,,B) scanf("%d%d%d",&s[i].u,&s[i].v,&s[i].cost);
sort(s+,s+B+,cmp);
rep(i,,B) {
int fu=find(s[i].u),fv=find(s[i].v);
if(fu==fv) s[++tot]=s[i];
else { ff[fu]=fv;
add(s[i].u,s[i].v,s[i].cost);
add(s[i].v,s[i].u,s[i].cost);
}
}
B=tot; tot=;
dfs1(,); dfs2(,);
build(,,N); tot=;
rep(i,,B){
tot=Query(s[i].u,s[i].v);
ans+=(ll)tot*s[i].cost;
}
if(Mx[]==inf) puts("-1");
else printf("%lld\n",ans);
return ;
}
Hihocoder1883 : 生成树问题(并查集+树剖+线段树)的更多相关文章
- 【bzoj4399】魔法少女LJJ 并查集+权值线段树合并
题目描述 在森林中见过会动的树,在沙漠中见过会动的仙人掌过后,魔法少女LJJ已经觉得自己见过世界上的所有稀奇古怪的事情了LJJ感叹道“这里真是个迷人的绿色世界,空气清新.淡雅,到处散发着醉人的奶浆味: ...
- BZOJ_4551_[Tjoi2016&Heoi2016]树_树剖+线段树
BZOJ_4551_[Tjoi2016&Heoi2016]树_树剖+线段树 Description 在2016年,佳媛姐姐刚刚学习了树,非常开心.现在他想解决这样一个问题:给定一颗有根树(根为 ...
- LOJ#3088. 「GXOI / GZOI2019」旧词(树剖+线段树)
题面 传送门 题解 先考虑\(k=1\)的情况,我们可以离线处理,从小到大对于每一个\(i\),令\(1\)到\(i\)的路径上每个节点权值增加\(1\),然后对于所有\(x=i\)的询问查一下\(y ...
- BZOJ_2238_Mst_树剖+线段树
BZOJ_2238_Mst_树剖+线段树 Description 给出一个N个点M条边的无向带权图,以及Q个询问,每次询问在图中删掉一条边后图的最小生成树.(各询问间独立,每次询问不对之后的询问产生影 ...
- BZOJ_2157_旅游_树剖+线段树
BZOJ_2157_旅游_树剖+线段树 Description Ray 乐忠于旅游,这次他来到了T 城.T 城是一个水上城市,一共有 N 个景点,有些景点之间会用一座桥连接.为了方便游客到达每个景点但 ...
- 【BZOJ5210】最大连通子块和 树剖线段树+动态DP
[BZOJ5210]最大连通子块和 Description 给出一棵n个点.以1为根的有根树,点有点权.要求支持如下两种操作: M x y:将点x的点权改为y: Q x:求以x为根的子树的最大连通子块 ...
- [LNOI2014]LCA(树剖+线段树)
\(\%\%\% Fading\) 此题是他第一道黑题(我的第一道黑题是蒲公英) 一直不敢开,后来发现是差分一下,将询问离线,树剖+线段树维护即可 \(Code\ Below:\) #include ...
- [CF1007D]Ants[2-SAT+树剖+线段树优化建图]
题意 我们用路径 \((u, v)\) 表示一棵树上从结点 \(u\) 到结点 \(v\) 的最短路径. 给定一棵由 \(n\) 个结点构成的树.你需要用 \(m\) 种不同的颜色为这棵树的树边染色, ...
- BZOJ3531-[Sdoi2014]旅行(树剖+线段树动态开点)
传送门 完了今天才知道原来线段树的动态开点和主席树是不一样的啊 我们先考虑没有宗教信仰的限制,那么就是一个很明显的树剖+线段树,路径查询最大值以及路径和 然后有了宗教信仰的限制该怎么做呢? 先考虑暴力 ...
- 【bzoj4699】树上的最短路(树剖+线段树优化建图)
题意 给你一棵 $n$ 个点 $n-1$ 条边的树,每条边有一个通过时间.此外有 $m$ 个传送条件 $(x_1,y_1,x_2,y_2,c)$,表示从 $x_1$ 到 $x_2$ 的简单路径上的点可 ...
随机推荐
- [ios][swift]UIButton
参考:http://www.hangge.com/blog/cache/detail_529.html
- Python将某文件夹及其子文件夹下某种格式的文件移动到另一个指定的文件下
主要是理解好上面的1~3点的内容,理解三个返回值所代表的意思.如果不清楚的话,可以在代码的for循环的第一句注释输出看看各个代表的是什么 再者就是对 shutil.copy(file_path,new ...
- Linux环境下 RabbitMQ 的下载与安装
0 环境 CentOS7 RabbitMQ 3.6.5 erlang 18.3 socat rabbitmq是使用erlang语言编写的,所以需要先安装erlang,其次rabbitmq安装依赖于so ...
- Shell需注意的语法问题
1.文件头声明别漏掉#和! #!/bin/bash 2.赋值语句①=号两端不能有空格(判断语句=号两端必须有空格)②使用变量必须使用符号$ var1=valecho $var1 3.if语句写错下面任 ...
- hihoCoder 1636 Pangu and Stones
hihoCoder 1636 Pangu and Stones 思路:区间dp. 状态:dp[i][j][k]表示i到j区间合并成k堆石子所需的最小花费. 初始状态:dp[i][j][j-i+1]=0 ...
- Codeforces 559B - Equivalent Strings
559B - Equivalent Strings 思路:字符串处理,分治 不要用substr(),会超时 AC代码: #include<bits/stdc++.h> #include&l ...
- 增加centos7.3上安装php7的php-soap扩展
代码传到正式服务器上去就:Class 'SoapClient' not found,只能是soap扩展没装! 因为服务器上面的PHP是7.1.11的,所以soap也要装7.1.11的,否则会冲突 ...
- golang martini 源码阅读笔记之inject
martini是go语言写的一个超级轻量的web开源框架,具体源码可在github搜索找到.13年那会开始接触go语言时有稍微看过这个框架,由于之后没有继续使用go就慢慢忽略了,最近由于手头项目可能会 ...
- mxnet(gluon) 实现DQN简单小例子
参考文献 莫凡系列课程视频 增强学习入门之Q-Learning 关于增强学习的基本知识可以参考第二个链接,讲的挺有意思的.DQN的东西可以看第一个链接相关视频.课程中实现了Tensorflow和pyt ...
- UVA-11214 Guarding the Chessboard (迭代加深搜索)
题目大意:在一个国际象棋盘上放置皇后,使得目标全部被占领,求最少的皇后个数. 题目分析:迭代加深搜索,否则超时. 小技巧:用vis[0][r].vis[1][c].vis[2][r+c].vis[c- ...