看了标答感觉思路清晰了许多,用并查集来维护全联通块的点数和边权和。

用另一个up[]数组(也是并查集)来保证每条边不会被重复附权值,这样我们只要将询问按权值从小到大排序,一定能的到最小的边权和与联通块中的点数。

下面是过程分析。过程中一共运用了两个并查集。

[数据]
1
10 3
1 2
1 3
2 4
2 5
3 6
3 7
4 8
5 9
5 10
9 6 3 1 50
1 4 2 5 20
9 10 8 10 40
[分析]
首先我们将图构建出来

我们将m次询问按权值从小到大排序后:

1 4 2 5 20
9 10 8 10 40
9 6 3 1 50

对于(1,4) (2,5) 20 这一组询问:

  我们做如下操作, 首先查找1,4的lca(此例中lca即为1),先合并4与lca之间的边:利用up[] 往上合并直到超过或者到达lca。在往上合并的过程中,可以把下面的边权合并至父节点。利用up[]的路径压缩性质,下次再访问up[4],up[2]时会直接跳至1。此时cnt[1]已经加上了了从4到1路径中点的个数,cost[1]里面加上了了从4到1所有边权的和(利用一个并查集维护)。经过上述操作 parent[4] = parent[2] = 1, up[4] = up[2] = 1。同理我们继续合并1与lca(lca=1);

  合并完之后,我们处理2,5这一对点,lca(2,5)=2; 首先我们合并5与lca之间的边,利用up[5]=5,我们在并查集中合并5与anc[5][0](是倍增lca,所以即为5的2^0级父节点) 我们知道anc[5][0]=2;所以在merge(5,anc[5][0],cost)的过程中,实际上是把边权和点数附加到了anc[5][0]的父节点上,即1(详见上一段操作中,2已经被合并至1上,即parent[2] = 1),也就是说cnt[1]记录了5到lca路径中点的个数,cost[1]里面加上了5到lca所有边权的和,且经过这一段操作,up[5] = 1, parent[5] = 1。同理,我们继续合并2与lca(lca=2)。

对于9 10 8 10 40 这一组询问,

  lca[9,10]=5,照上面的过程合并中将{1,2,4,5,9 ,10}都加进了父节点中,在处理8,10(lca(8,10)=2)中我们发现,810路径之中有已经被赋值的边且肯定比当前要赋的值(因为询问是按权值从小到大来的),这个时候 up数组 就要发挥作用了。第一次询问up[8] = 8,合并[8,anc[8][0]=4],下一次询问up[8] = 4,合并[4 , anc[4][0]=2],这个时候就,因为parent[2] = 1,所以8被记录进了cnt[1],且边权也被加到了cost[1],再之后up[4] = 1,直接跳到了lca=2节点的上面,提示我们不需要再继续合并了(deep[1]<deep[2])。之后都进行相似的操作就可以得出答案 [9, 280]。

就像这样 , 9 10 8 10 50这组询问实际上只将3条蓝色边赋值成了40,橙色的边早已赋值成了更优的20。

  实际上,up数组保存的是与自己不在一个联通块(另一个并查集维护联通快性质)的且最接近自己的父节点,比如此例子中up[4]=1,up[8]=1,(此例子中较特殊,已经不存在深度更小的顶点了,假如第一组询问换成2 4 2 5 20,那么up[2] = up[4] = 1)直接跳到了最高点,提示我们不需要继续合并了,之后的边肯定都已经赋过值了,且值更优。

/*hdu6074[并查集+LCA+思维] 2017多校4*/
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
struct node {
int a, b, c, d;
LL w;
bool operator < (node& x) {
return w < x.w;
}
} q[];
vector<int> G[];
int T, m, n;
int up[], p[], deep[], anc[][];
LL cnt[], cost[];
void init() {
for (int i = ; i <= n; i++) {
G[i].clear();
}
memset(deep, , sizeof(deep));
for (int i = ; i <= n; i++)
cost[i]=,cnt[i]=,p[i] = up[i] = i;
}
int getfa(int x) {
return p[x] == x ? x : p[x] = getfa(p[x]);
}
int getup(int x) {
return up[x] == x ? x : up[x] = getup(up[x]);
}
void dfs(int u, int fa) {
anc[u][] = fa;
for (int i = ; i < ; i++) {
anc[u][i] = anc[anc[u][i - ]][i - ];
}
for (int i = ; i < (int)G[u].size(); i++) {
int v = G[u][i];
if (v == fa) continue;
deep[v] = deep[u] + ;
dfs(v, u);
}
}
int lca(int u, int v) {
if (deep[u] < deep[v]) swap(u, v);
for (int i = ; ~i; i--) {
if (deep[v] <= deep[anc[u][i]]) {
u = anc[u][i];
}
}
if (u == v) return u;
for (int i = ; ~i; i--) {
if (anc[u][i] != anc[v][i]) {
u = anc[u][i];
v = anc[v][i];
}
}
return anc[u][];
}
void merge(int u, int v, LL w) {
int x = getfa(u);
int y = getfa(v);
if (x == y) return;
p[x] = y;
cnt[y] += cnt[x];
cost[y] += cost[x] + w;
}
void jump(int u, int v, LL w) {
for (;;) {
u = getup(u);
if (deep[u] <= deep[v]) return;
merge(u, anc[u][], w);
up[u] = anc[u][];
}
}
void solve() {
dfs(, );
sort(q + , q + m + );
for (int i = ; i <= m; i++) {
int k = lca(q[i].a, q[i].b);
//cout << q[i].w << endl;
jump(q[i].a, k, q[i].w);
jump(q[i].b, k, q[i].w);
k = lca(q[i].c, q[i].d);
jump(q[i].c, k, q[i].w);
jump(q[i].d, k, q[i].w);
merge(q[i].a, q[i].c, q[i].w);
}
printf("%lld %lld\n",cnt[getfa()],cost[getfa()]);
}
int main() {
scanf("%d", &T);
while (T--) {
int u, v;
scanf("%d%d", &n, &m);
init();
for (int i = ; i < n; i++) {
scanf("%d%d", &u, &v);
G[u].push_back(v);
G[v].push_back(u);
}
for (int i = ; i <= m; i++) {
scanf("%d%d%d%d%lld", &q[i].a, &q[i].b, &q[i].c, &q[i].d, &q[i].w);
}
solve();
}
return ;
}
/*
2
10 3
1 2
1 3
2 4
2 5
3 6
3 7
4 8
5 9
5 10
1 4 2 5 20
9 10 8 10 40
9 6 3 1 50
10 1
1 2
1 3
2 4
2 5
3 6
3 7
4 8
5 9
5 10
1 7 9 10 20
*/

顺便附上st表lca的版本.

#include <bits/stdc++.h>
using namespace std;
const int MAX_N = ;
typedef long long LL; struct node {
int a, b, c, d;
LL w;
bool operator < (node& x) {
return w < x.w;
}
} q[];
int pos[MAX_N], dep[MAX_N << ], h[MAX_N << ], up[MAX_N], p[MAX_N], s[MAX_N];
int st[MAX_N << ][], len[MAX_N << ], tot = , deep[MAX_N];
vector<int> G[MAX_N];
int T, m, n;
LL cnt[MAX_N], cost[MAX_N];
void init() {
tot = ;
for (int i = ; i <= n; i++) {
G[i].clear();
}
for (int i = ; i <= n; i++)
cost[i] = , cnt[i] = , p[i] = up[i] = i;
}
int getfa(int x) {
return p[x] == x ? x : p[x] = getfa(p[x]);
}
int getup(int x) {
return up[x] == x ? x : up[x] = getup(up[x]);
}
void dfs(int u, int fa, int dps) {
s[u] = fa;
deep[u]=dps;
h[++tot] = u, pos[u] = tot, dep[tot] = dps;
for (int i = ; i < (int)G[u].size(); i++) {
int v = G[u][i];
if (v == fa) continue;
dfs(v, u, dps + );
h[++tot] = u;
dep[tot] = dps;
}
}
void st_init() {
len[] = -;
for (int i = ; i <= tot; i++) {
st[i][] = i;
len[i] = ((i & (i - )) == ) ? len[i - ] + : len[i - ];
}
for (int j = ; j <= len[tot]; j++) {
for (int i = ; i + ( << j) - < tot; i++) {
int a = st[i][j - ], b = st[i + ( << (j - ))][j - ];
st[i][j] = dep[a] < dep[b] ? a : b;
}
}
}
int query(int l, int r) {
int k = len[r - l + ];
int a = st[l][k], b = st[r - ( << k) + ][k];
return dep[a] < dep[b] ? a : b;
}
int lca(int u, int v) {
int l = pos[u], r = pos[v];
if (l > r) swap(l, r);
return h[query(l, r)];
}
void merge(int u, int v, LL w) {
int x = getfa(u);
int y = getfa(v);
if (x == y) return;
p[x] = y;
cnt[y] += cnt[x];
cost[y] += cost[x] + w;
}
void jump(int u, int v, LL w) {
for (;;) {
u = getup(u);
if (deep[u] <= deep[v]) return;
merge(u, s[u], w);
up[u] = s[u];
//cout << u << ' ' << s[u] << endl;
}
}
void solve() {
dfs(, , );
st_init();
sort(q + , q + m + );
for (int i = ; i <= m; i++) {
int k = lca(q[i].a, q[i].b);
//cout << k << endl;
jump(q[i].a, k, q[i].w);
jump(q[i].b, k, q[i].w);
k = lca(q[i].c, q[i].d);
jump(q[i].c, k, q[i].w);
jump(q[i].d, k, q[i].w);
merge(q[i].a, q[i].c, q[i].w);
}
printf("%lld %lld\n", cnt[getfa()], cost[getfa()]);
}
int main() {
scanf("%d", &T);
while (T--) {
int u, v;
scanf("%d%d", &n, &m);
init();
for (int i = ; i < n; i++) {
scanf("%d%d", &u, &v);
G[u].push_back(v);
G[v].push_back(u);
}
for (int i = ; i <= m; i++) {
scanf("%d%d%d%d%lld", &q[i].a, &q[i].b, &q[i].c, &q[i].d, &q[i].w);
}
solve();
}
return ;
}

hdu6074[并查集+LCA+思维] 2017多校4的更多相关文章

  1. hdu 2874 Connections between cities (并查集+LCA)

    Connections between cities Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (J ...

  2. hdu6035[dfs+思维] 2017多校1

    /*hdu6035[dfs+思维] 2017多校1*/ //合并色块, 妙啊妙啊 #include<bits/stdc++.h> using namespace std; ; const ...

  3. HDU6074 Phone Call (并查集 LCA)

    Phone Call Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 524288/524288 K (Java/Others)Tota ...

  4. Gym 100814C Connecting Graph 并查集+LCA

    Description standard input/output Statements Alex is known to be very clever, but Walter does not be ...

  5. Network-POJ3694并查集+LCA

    Network Time Limit: 5000MS   Memory Limit: 65536K       Description A network administrator manages ...

  6. [并查集+LCA USACO18OPEN ] Disruption

    https://www.luogu.org/problemnew/show/P4374 一看这道题就是一个妙题,然后题解什么树链剖分...珂朵莉树... 还不如并查集来的实在!我们知道并查集本来就是路 ...

  7. Mobile Phone Network CodeForces - 1023F(并查集lca+修改环)

    题意: 就是有几个点,你掌控了几条路,你的商业对手也掌控了几条路,然后你想让游客都把你的所有路都走完,那么你就有钱了,但你又想挣的钱最多,真是的过分..哈哈 游客肯定要对比一下你的对手的路 看看那个便 ...

  8. 习题:过路费(kruskal+并查集+LCA)

    过路费  [问题描述]在某个遥远的国家里,有 n 个城市.编号为 1,2,3,…,n.这个国家的政府修 建了 m 条双向道路,每条道路连接着两个城市.政府规定从城市 S 到城市 T 需 要收取的过路费 ...

  9. BZOJ 4668 冷战(按秩合并并查集+LCA)

    4668: 冷战 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 627  Solved: 303[Submit][Status][Discuss] D ...

随机推荐

  1. UVA11478 Halum (差分约束)

    每次操作是独立的,而且顺序并不影响,作用在同一个结点上的d可以叠加,所以令x(u) = sigma(dui). 最后就是要确定所有的x(u). 因为m越大,满足条件的边就越少,二分答案m. 对于一条边 ...

  2. springmvc 的原理分析

    1. 用户发送请求至前端控制器(DispatcherServlet) 2.DispatcherServlet 将受到的请求调用HandlerMapping 处理映射器 3.处理器映射器根据配置注解找到 ...

  3. cpp代码调试,调试扑克牌的代码

    #include <iostream> #include <vector> #include <algorithm> using namespace std; cl ...

  4. appium---启动app

    自动化测试是测试人员必备的一项技能,所谓的自动化就是通过代码完成了手工的操作,今天就总结下如何通过python启动app 环境条件 1.安装python:下载地址 2.安装JDK:下载地址 3.安装A ...

  5. 从输入url到页面加载完成发生了什么详解

    这是一道经典的面试题,这道题没有一个标准的答案,它涉及很多的知识点,面试官会通过这道题了解你对哪一方面的知识比较擅长,然后继续追问看看你的掌握程度.当然我写的这些也只是我的一些简单的理解,从前端的角度 ...

  6. php面试相关

    22.描述一下大流量高并发量网站的解决方案 答: 1.确认服务器硬件是否足够支持当前的流量. 2.使用memcache缓存技术,将动态数据缓存到内存中,动态网页直接调用这些文件,而不必在访问数据库. ...

  7. HTML5 跨文档消息传输

    对窗口对象的message事件进行监听 window.addEventListener("message", function(event) { // 处理程序代码 }, fals ...

  8. iOS与JS相互传值与交互

    JavaScriptCore是webkit的一个重要组成部分,主要是对JS进行解析和提供执行环境.iOS7后苹果在iPhone平台推出,极大的方便了我们对js的操作.我们可以脱离webview直接运行 ...

  9. Leetcode 20 有效的括号valid-parentheses(栈)

    给定一个只包括 '(',')','{','}','[',']' 的字符串,判断字符串是否有效. 有效字符串需满足: 左括号必须用相同类型的右括号闭合. 左括号必须以正确的顺序闭合. 注意空字符串可被认 ...

  10. numpy学习(一)

    numpy数据类型 # numpy创建对象,numpy创建的对象是n阶矩阵,类似python中列表的嵌套 nd = np.array([[1,2,3,4,5],[2,3,4,6,5]])nd 结果: ...