题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3649


这题倍增维护信息之多,也能算是一道毒瘤题了……

解题思路

这题分为两个部分,第一个是最大生成树,第二个是若干个询问,问在生成树上 $ x->y $ 的路径上最大的 $ ck-cj (ck >= cj, j <= k) $ 。

第一个部分我想就不用多讲,直接跑最小生成树(只是把最小换成了最大)。

第二个部分,重点在于\((ck>=cj,j<=k)\)这个限制。由于题目特性,看起来是逃不过倍增的了。首先,我们自然地将 $ x->y $ 分成了 $ x->lca(x,y)->y $ 。通过这个分段,我们观察我们倍增时需要维护那些东西。仔细分析发现一共有如下几样:

  • $ d[x][i].d $ :维护 $ x $ 的第 $ 2^i $ 个祖先
  • $ d[x][i].maxnum $ :维护从 $ x $ 到 $ x $ 的第 $ 2^i $ 个祖先中的最大值
  • $ d[x][i].minnum $ :维护从 $ x $ 到 $ x $ 的第 $ 2^i $ 个祖先中的最小值
  • $ d[x][i].max_up $ :维护从 $ x $ 到 $ x $ 的第 $ 2^i $ 个祖先中的最大差值(由下至上)
  • $ d[x][i].max_dn $ :维护从 $ x $ 到 $ x $ 的第 $ 2^i $ 个祖先中的最大差值(由上至下)

对于后两条的解释:从公式中可以看出,相减具有方向性,而且 $ x->lca(x,y) $ 与 $ lca(x,y)->y $ 方向不同。

另行说明:本文 $ d[x][i] $ 所含信息不包括 $ x $ (这样可以很方便地分成两个不相交的区间)(或许可以不这么做qwq)

然后我们考虑如何维护这五个值。前三个没有什么大问题,后两个要注意整合时要考虑三个值,千万不要漏了两个区间并中的值(最大值与最小值相减)。以下给出维护这五个值的递推式:

  • $ d[x][i].d = d[d[x][i - 1].d][i - 1].d $
  • $ d[x][i].maxnum = max(d[x][i - 1].maxnum, d[d[x][i - 1].d][i - 1].maxnum) $
  • $ d[x][i].minnum = min(d[x][i - 1].minnum, d[d[x][i - 1].d][i - 1].minnum) $
  • $ d[x][i].max_up = max(d[x][i - 1].max_up, d[d[x][i - 1].d][i - 1].max_up, d[d[pos][i - 1].d][i - 1].maxnum - d[pos][i - 1].minnum) $
  • $ d[pos][i].max_up = max(d[pos][i - 1].max_up, d[d[pos][i - 1].d][i - 1].max_up, d[pos][i - 1].maxnum - d[d[pos][i - 1].d][i - 1].minnum) $

我们可以以类似的方法合并 $ x->lca(x,y) $ 和 $ lca(x,y)->y $ 两段区间,得到最后的答案。


参考程序

tip:程序中 $ x -> lca(x,y) -> y $ 是以 $ y -> lca(x,y) -> x $ 的顺序做的。

#include <cstdio>
#include <iostream>
#include <cmath>
#include <sstream>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAXN = 30010, MAXM = 50010;
const int INF = 1000000000;
int n, m, b[MAXN];
struct Edge {
int x, y, z;
Edge(int x_ = 0, int y_ = 0, int z_ = 0) { x = x_; y = y_; z = z_; return; }
};
Edge edge[MAXM];
int x, y, z;
bool cmp(Edge x, Edge y) {
return x.z > y.z;
}
int father[MAXN];
int lp, f[MAXN], lin[MAXN << 1], nxt[MAXN << 1];
inline void add(int x, int y) { lin[++lp] = y; nxt[lp] = f[x]; f[x] = lp; return; }
int ans;
int get_father(int x) {
if(father[x] == x) return x;
father[x] = get_father(father[x]);
return father[x];
}
int q; struct Node {
int d, maxnum, minnum, max_dn, max_up;
};
Node d[MAXN][16];
int deep[MAXN];
void build_tree(int pos, int fa) {//建树,同事处理完成倍增相关的信息
deep[pos] = deep[fa] + 1;
d[pos][0].d = fa;
d[pos][0].maxnum = b[fa];
d[pos][0].minnum = b[fa];
d[pos][0].max_dn = -INF;
d[pos][0].max_up = -INF;
for(int i = 1; i < 16; i++) {
d[pos][i].d = d[d[pos][i - 1].d][i - 1].d;
d[pos][i].maxnum = max(d[pos][i - 1].maxnum, d[d[pos][i - 1].d][i - 1].maxnum);
d[pos][i].minnum = min(d[pos][i - 1].minnum, d[d[pos][i - 1].d][i - 1].minnum);
d[pos][i].max_dn = max(d[pos][i - 1].max_dn, d[d[pos][i - 1].d][i - 1].max_dn);
d[pos][i].max_dn = max(d[pos][i].max_dn, d[d[pos][i - 1].d][i - 1].maxnum - d[pos][i - 1].minnum);
d[pos][i].max_up = max(d[pos][i - 1].max_up, d[d[pos][i - 1].d][i - 1].max_up);
d[pos][i].max_up = max(d[pos][i].max_up, d[pos][i - 1].maxnum - d[d[pos][i - 1].d][i - 1].minnum);
}
for(int t = f[pos]; t; t = nxt[t]) {
if(lin[t] == fa) continue;
build_tree(lin[t], pos);
}
return;
}
int get_lca(int x, int y) {//求最近公共祖先
if(deep[x] < deep[y]) swap(x, y);
for(int i = 15; i >= 0; i--)
if(deep[d[x][i].d] >= deep[y]) x = d[x][i].d;
if(x == y) return x;
for(int i = 15; i >= 0; i--)
if(d[x][i].d != d[y][i].d) x = d[x][i].d, y = d[y][i].d;
return d[x][0].d;
}
int recmin, recmax;
void go_up(int x, int y){//y->lca(x, y)
if(x == y) return;//由于倍增中设定是不包含x的
recmax = max(recmax, b[x]);
for(int i = 15; i >= 0; i--) {
if(deep[d[x][i].d] <= deep[y]) continue;
ans = max(ans, recmax - d[x][i].minnum);
recmax = max(recmax, d[x][i].maxnum);
ans = max(ans, d[x][i].max_up);
x = d[x][i].d;
}
return;
}
void go_down(int x, int y){//lca(x, y)->x
recmin = min(recmin, b[x]);
for(int i = 15; i >= 0; i--) {
if(deep[d[x][i].d] < deep[y]) continue;
ans = max(ans, d[x][i].maxnum - recmin);
recmin = min(recmin, d[x][i].minnum);
ans = max(ans, d[x][i].max_dn);
x = d[x][i].d;
}
return;
}
int main() {
while(scanf("%d", &n) == 1) {//多组数据
memset(b, 0, sizeof(b));
lp = 0;
memset(f, 0, sizeof(f)); memset(lin, 0, sizeof(lin)); memset(nxt, 0, sizeof(nxt));
memset(edge, 0, sizeof(edge));
memset(deep, 0, sizeof(deep));
memset(d, 0, sizeof(d));//初始化 for(int i = 1; i <= n; i++) father[i] = i;
for(int i = 1; i <= n; i++) scanf("%d", &b[i]);
scanf("%d", &m);
for(int i = 1; i <= m; i++) {
scanf("%d%d%d", &x, &y, &z);
edge[i] = Edge(x, y, z);
}
sort(edge + 1, edge + m + 1, cmp);
z = 1;
ans = 0;
for(int i = 1; i < n; i++) {
x = get_father(edge[z].x);
y = get_father(edge[z].y);
while(x == y) {
x = get_father(edge[++z].x);
y = get_father(edge[z].y);
}
ans += edge[z].z;
father[y] = x;
add(edge[z].x, edge[z].y);
add(edge[z].y, edge[z].x);//加入树边
z++;
}
printf("%d\n", ans);//最大生成树(库鲁斯卡尔) build_tree(1, 1);//建树,同事处理完成倍增相关的信息
scanf("%d", &q);
for(int i = 1; i <= q; i++) {
scanf("%d%d", &x, &y);
int lca = get_lca(x, y);//求最近公共祖先
ans = 0; recmin = INF; recmax = -INF;
go_up(y, lca);//y->lca(x, y)
go_down(x, lca);//lca(x, y)->x
ans = max(ans, recmax - recmin);//合并答案
printf("%d\n", ans);
}
}
return 0;
}

ZOJ3649 Social Net的更多相关文章

  1. 【做题】zoj3649 Social Net——倍增

    这题是吴老师推荐的,于是我就去做了. 根据题意,在完成最大生成树后,对于树上从x到y的一条路径,求出最大的ck-cj(j<=k,ci为路径上第i个点的权值). 我一开始的想法是二分,记路径xy的 ...

  2. [ZOJ3649]Social Net 题解

    前言 这道题目珂以说是很毒瘤了. 题解 首先克鲁斯卡尔求最大生成树,输出边权和. 倍增维护四个值:   链上最大值/最小值   链向上/向下最大差值 当然祖先是肯定要维护的. 然后把一条链经LCA分成 ...

  3. 讲座:Influence maximization on big social graph

    Influence maximization on big social graph Fanju PPT链接: social influence booming of online social ne ...

  4. Call for Papers IEEE/ACM International Conference on Advances in Social Network Analysis and Mining (ASONAM)

    IEEE/ACM International Conference on Advances in Social Network Analysis and Mining (ASONAM) 2014 In ...

  5. 微信小程序想要的是无法监测的流量dark social

    “微信小程序”将带来什么样的变化?就单单的是一个超级Web app?还是只是为了给大家手机节省一些空间?腾讯想要的是高达70%以上的“无法监测的巨大流量”,称之为“dark social”(暗社交). ...

  6. 想一想social VR might just work

    昨天玩了Oculus上的Casino VR(其实之前就知道这个瑞士公司,也下过standalone的PC client). 几把下来,居然觉得fun,总结起来: 1.是在一个immersive的环境中 ...

  7. A List of Social Tagging Datasets Made Available for Research

    This list is not exhaustive - help expand it! Social Tagging Systems Research Group Source Year Obta ...

  8. Social Media POC KT Session

    地址: 1. http://c0048925.itcs.hp.com:8080/datamining/report/brandfocus.html Social Media POC是针对Social ...

  9. 项目总结笔记系列 Social Hub KT Session2

    KT Session2: 主要是代码的实现(KT is knowledge Transfer) 如图所示,在整个Social Hub项目中,我们的项目Data Feed Service处于承上启下的作 ...

随机推荐

  1. python基础数据类型和初级应用

    1.整数: int -- 计算和比较 2 -- 10 推位 8421 20 21 -- 2**7 10 - 2 bit_length 二进制的有效占用位数 # 123 # 计算和比较 # 14 0 # ...

  2. VMware 无法开机

    无法打开磁盘 虚拟机无法打开磁盘 "或者某一个快照所依赖的磁盘 原因:未能锁定文件"的解决办法 很多人在使用虚拟机是都会遇到“无法打开磁盘" x:\*\*vmdk &qu ...

  3. BIML 101 - ETL数据清洗 系列 - BIML 快速入门教程 - 将文本文件(csv)数据导进数据库

    第二节 将文本文件数据导进数据库 该小节介绍如何用BIML生成ssis包,将货币文本导入到数据库currency的表中. SSIS组件: Connection Manager组建管理connectio ...

  4. Redis安全策略

    1. 开启redis密码认证,并设置高复杂度密码 描述 redis在redis.conf配置文件中,设置配置项requirepass, 开户密码认证. redis因查询效率高,auth这种命令每秒能处 ...

  5. Java Lock的使用

    + ReentrantLock类的使用 + ReentrantReadWriteLock类的使用 1. 使用ReentrantLock类 ReentrantLock类能够实现线程之间同步互斥,并且在扩 ...

  6. Design Support库中的控件

    1.NavigationView滑动菜单 2.FloatIngActionButton悬浮按钮 3.Snackbar二次交互提示的按钮 4.Coordinatorlayout,监听子控件的各种事件(加 ...

  7. Linux小知识:rm -rf/*会将系统全部删除吗

    Linux小知识:rm -rf/*会将系统全部删除吗 本文是学习笔记,视频地址为:https://www.bilibili.com/video/av62839850 执行上面的命令并不会删除所有内容( ...

  8. jQuery制作弹出窗(模态框)

    来源:(二少)在南极 ##index.html <!DOCTYPE html><html lang="zh"><head> <meta c ...

  9. Android系统修改之葡萄牙沃达丰One Net服务问题处理

    客户反馈的葡萄牙沃达丰的OneNet服务问题 Vodafone Portugal have a service (One Net) for enterprise customers that used ...

  10. Java面试01

    一.谈谈你对java的理解 1.平台无关性,一次编译到处运行 2.GC 3.语言特性 4.面向对象 5.类库 6.异常处理 二.Java如何做到一次编译到处运行?(如何做到平台无关性) 首先我们先来编 ...