[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) ...
随机推荐
- c++自定义时间输出
#include <time.h> time_t timep; struct tm *p; time(&timep); p=localtime(&timep); int l ...
- c语言1作业07
这个作业属于那个课程 C语言程序设计II 这个作业要求在哪里 https://edu.cnblogs.com/campus/zswxy/CST2019-4/homework/9932 我在这个课程的目 ...
- HDU 1159 Common Subsequence (动态规划、最长公共子序列)
Common Subsequence Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Other ...
- cpu和内存的使用率统计
统计cpu和内存一个月的平均使用率: #!/bin/bash totalcpu_rate=0.0 totalmem_rate=0.0 num_days=$(ls -l /var/log/sa/sa[0 ...
- Luogu P4602 [CTSC2018]混合果汁
题目 把果汁按美味度降序排序,以单价为下标插入主席树,记录每个节点的\(sum\)果汁升数和\(val\)果汁总价. 每次询问二分最小美味度,查询美味度大于等于\(mid\)的总体积为\(L\)的最低 ...
- git diff 命令用法
理解git diff的前提,首先要理解git中工作区,暂存区,本地版本库的概念,如果头脑中有这些概念,接着往下读. git diff test.c 用来查看工作区和暂存区中test.c文件的区别. g ...
- filebeat->redis->logstash->elasticsearch->kibana
整体流程 filebeat收集openresty应用日志传输到Redis集群中 Logstash从Redis集群中拉取数据,并传输到Elasticsearch集群 使用Kibana可视化索引 使用El ...
- Homebrew学习(二)之安装、卸载、更新
安装 1.网上的安装方法都是用curl,从官网找到命令复制到终端,然后回车,结果报错请求超时 /usr/bin/ruby -e "$(curl -fsSL https://raw.githu ...
- BZOJ 3118 Orz the MST
权限题qwq 如果我们要使得某棵生成树为最小生成树,那么上面的边都不能被替代,具体的,对于一个非树边,它的权值要\(\ge\)它两端点在树上的路径上的所以边的权值,所以对于每个非树边就可以对一些树边列 ...
- 六、while循环
案例1: do while 循环 很少用到. for循环和while循环用的最多.