[ZOJ3649]Social Net 题解
前言
这道题目珂以说是很毒瘤了。
题解
首先克鲁斯卡尔求最大生成树,输出边权和。
倍增维护四个值:
链上最大值/最小值
链向上/向下最大差值
当然祖先是肯定要维护的。
然后把一条链经LCA分成两半。
分向上向下按照之前维护的值动态计算。
最后注意多组数据的维护(清空数组,边数之类的变量)。
代码
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int LOG_N = 15;
const int INF = 1 << 28;
namespace fast_IO{
const int OUT_LEN = 10000000;
char obuf[OUT_LEN], *oh = obuf, *lastout = obuf + OUT_LEN - 1;
inline void putchar_(const char x){if(oh == lastout) fwrite(obuf, 1, oh - obuf, stdout), oh = obuf; *oh ++= x;}
inline void flush(){fwrite(obuf, 1, oh - obuf, stdout);}
void write(int x){
if (x < 0) putchar_('-'), x = -x;
if (x > 9) write(x / 10);
putchar_(x % 10 + '0');
}
}
using namespace fast_IO;
struct Node{
int anc;
int min, max;
int udif, ddif;
} f[30005][LOG_N + 1];
struct PreEdge{
int u, v, w;
} pre_edge[50005];
bool operator < (const PreEdge &a, const PreEdge &b){
return a.w > b.w;
}
struct Edge{
int to, val, next;
} edges[60005];
int head[30005], edge_num;
inline void addEdge(int from, int to, int val){
edges[++edge_num] = (Edge){to, val, head[from]};
head[from] = edge_num;
}
int n;
int c[30005];
int fa[30005];
int getF(int u){
if (fa[u] == u) return u;
return (fa[u] = getF(fa[u]));
}
int deep[30005];
void preDFS(int u, int fat){
deep[u] = deep[fat] + 1;
f[u][0] = (Node){fat, c[fat], c[fat], -INF, -INF};
for (int i = 1; i <= LOG_N; ++i)
f[u][i] = (Node){
f[f[u][i - 1].anc][i - 1].anc,
min(f[u][i - 1].min, f[f[u][i - 1].anc][i - 1].min), max(f[u][i - 1].max, f[f[u][i - 1].anc][i - 1].max),
max(max(f[u][i - 1].udif, f[f[u][i - 1].anc][i - 1].udif), f[u][i - 1].max - f[f[u][i - 1].anc][i - 1].min),
max(max(f[u][i - 1].ddif, f[f[u][i - 1].anc][i - 1].ddif), f[f[u][i - 1].anc][i - 1].max - f[u][i - 1].min)
};
for (int c_e = head[u]; c_e; c_e = edges[c_e].next){
int v = edges[c_e].to;
if (v != fat)
preDFS(v, u);
}
}
int LCA(int x, int y){
if (deep[x] < deep[y]) swap(x, y);
for (int i = LOG_N; ~i; --i)
if (deep[f[x][i].anc] >= deep[y]) x = f[x][i].anc;
if (x == y) return x;
for (int i = LOG_N; ~i; --i)
if (f[x][i].anc != f[y][i].anc) x = f[x][i].anc, y = f[y][i].anc;
return f[x][0].anc;
}
int ans_min, ans_max;
int ans;
void getUp(int x, int y){
ans_max = max(ans_max, c[x]);
for (int i = LOG_N; i >= 0; --i){
if (deep[f[x][i].anc] > deep[y]){
ans = max(ans, ans_max - f[x][i].min);
ans_max = max(ans_max, f[x][i].max);
ans = max(ans, f[x][i].udif);
x = f[x][i].anc;
}
}
}
void getDown(int x, int y){
ans_min = min(ans_min, c[x]);
for (int i = LOG_N; i >= 0; --i){
if (deep[f[x][i].anc] >= deep[y]){
ans = max(ans, f[x][i].max - ans_min);
ans_min = min(ans_min, f[x][i].min);
ans = max(ans, f[x][i].ddif);
x = f[x][i].anc;
}
}
}
inline void init(){
memset(c, 0, sizeof(c));
memset(f, 0, sizeof(f));
memset(edges, 0, sizeof(edges));
memset(pre_edge, 0, sizeof(pre_edge));
memset(deep, 0, sizeof(deep));
memset(head, 0, sizeof(head));
edge_num = 0;
}
int main(){
while (scanf("%d", &n) == 1 && n){
init();
for (int i = 1; i <= n; ++i) scanf("%d", &c[i]), fa[i] = i;
int m; scanf("%d", &m);
for (int i = 0; i < m; ++i){
int u, v, w; scanf("%d %d %d", &u, &v, &w);
pre_edge[i] = (PreEdge){u, v, w};
}
sort(pre_edge, pre_edge + m); ans = 0;
for (int i = 0, j = 0; i < m; ++i){
int rtu = getF(pre_edge[i].u), rtv = getF(pre_edge[i].v);
if (rtu != rtv){
fa[rtu] = rtv; ans += pre_edge[i].w;
addEdge(pre_edge[i].u, pre_edge[i].v, pre_edge[i].w);
addEdge(pre_edge[i].v, pre_edge[i].u, pre_edge[i].w);
++j;
if (j == n - 1) break;
}
}
write(ans), putchar_('\n');
preDFS(1, 1);
int q; scanf("%d", &q);
while (q--){
int x, y; scanf("%d %d", &x, &y);
int xylca = LCA(x, y);
ans = 0, ans_min = INF, ans_max = -INF;
getUp(y, xylca), getDown(x, xylca);
ans = max(ans, ans_max - ans_min);
write(ans); putchar_('\n');
}
}
flush(); return 0;
}
[ZOJ3649]Social Net 题解的更多相关文章
- 【做题】zoj3649 Social Net——倍增
这题是吴老师推荐的,于是我就去做了. 根据题意,在完成最大生成树后,对于树上从x到y的一条路径,求出最大的ck-cj(j<=k,ci为路径上第i个点的权值). 我一开始的想法是二分,记路径xy的 ...
- ZOJ3649 Social Net
题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3649 这题倍增维护信息之多,也能算是一道毒瘤题了-- 解题思路 ...
- PAT甲题题解-1107. Social Clusters (30)-PAT甲级真题(并查集)
题意:有n个人,每个人有k个爱好,如果两个人有某个爱好相同,他们就处于同一个集合.问总共有多少个集合,以及每个集合有多少人,并按从大到小输出. 很明显,采用并查集.vis[k]标记爱好k第一次出现的人 ...
- Social Infrastructure Information Systems Division, Hitachi Programming Contest 2020 D题题解
将题意转换为一开始\(t = 0\),第\(i\)个操作是令\(t \leftarrow (a_i + 1) t + (a_i + b_i + 1)\).记\(A_i = a_i + 1, B_i = ...
- Social Infrastructure Information Systems Division, Hitachi Programming Contest 2020 C题题解
首先,我们将题目理解成若\(i\)与\(j\)距离恰好为\(3\),则不可能\(p_i \equiv p_j \equiv 1 \space or \space 2 (\bmod 3)\).这就相当于 ...
- [题解] Atcoder ABC 225 H Social Distance 2 生成函数,分治FFT
题目 首先还没有安排座位的\(m-k\)个人之间是有顺序的,所以先把答案乘上\((m-k)!\),就可以把这些人看作不可区分的. 已经确定的k个人把所有座位分成了k+1段.对于第i段,如果我们能求出这 ...
- PAT甲级题解(慢慢刷中)
博主欢迎转载,但请给出本文链接,我尊重你,你尊重我,谢谢~http://www.cnblogs.com/chenxiwenruo/p/6102219.html特别不喜欢那些随便转载别人的原创文章又不给 ...
- Tarjan & LCA 套题题目题解
刷题之前来几套LCA的末班 对于题目 HDU 2586 How far away 2份在线模板第一份倍增,倍增还是比较好理解的 #include <map> #include <se ...
- HDU3849-By Recognizing These Guys, We Find Social Networks Useful(无向图的桥)
By Recognizing These Guys, We Find Social Networks Useful Time Limit: 2000/1000 MS (Java/Others) ...
随机推荐
- jenkins pipline和jenkinsfile
Jenkins Pipeline(或简称为 "Pipeline")是一套插件,将持续交付的实现和实施集成到 Jenkins 中. Jenkins Pipeline 提供了一套可扩展 ...
- airflow部署
官网: http://airflow.apache.org/installation.html 原理: https://www.cnblogs.com/cord/p/9450910.html 安装: ...
- [转帖]56核Xeon Platinum 9200现身 - 英特尔有史以来最大的CPU封装
56核Xeon Platinum 9200现身 - 英特尔有史以来最大的CPU封装 https://www.cnbeta.com/articles/tech/835271.htm 当英特尔宣布上周正式 ...
- computer(树形dp || 树的直径)
Computer Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Su ...
- java tomcate 启动后cmd 出现乱码
今天windows 启动tomcat 后,出现cmd 乱码 尝试改cmd编码为UTF-8后无效,修改tomcat 注册表CodePage ,cmd 依然乱码, 后来把Conf 目录下的logging. ...
- IA-32 Assembly Language Reference Manual
Load Full Pointer (lds,les, lfs, lgs, and lss) lds{wl} mem[32|48], reg[16|32]les{wl} mem[32|48], reg ...
- Jade学习(一)之特性、安装
前言 流行的模板 PHP:Smarty SimpleTemplate Xtemplate Savant Java:Velocity FreeMarker Jbyte C#:Dotiquid Sharp ...
- ubuntu 安装mysql5.7
一.Windows mysql5.6 解压版 安装 关于widnows平台上的安装教程,可参考百度经验: 链接:https://jingyan.baidu.com/article/f3ad7d0ffc ...
- 修改文件夹的所有者为www
切换到root用户:su - root 修改文件所属用户和用户组:chown 用户:用户组 文件名如果用户和用户组是www,那么需要执行命令如下:chown www:www filename -R ( ...
- vue.js 分页加载,向上滑动,依次加载数据。
export default { layout: 'default', data(){ return{ page:1, pageSize:10, orderListArr:[], prodListLo ...