前言

这道题目珂以说是很毒瘤了。

题解

首先克鲁斯卡尔求最大生成树,输出边权和。

倍增维护四个值:

  链上最大值/最小值

  链向上/向下最大差值

当然祖先是肯定要维护的。

然后把一条链经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 题解的更多相关文章

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

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

  2. ZOJ3649 Social Net

    题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3649 这题倍增维护信息之多,也能算是一道毒瘤题了-- 解题思路 ...

  3. PAT甲题题解-1107. Social Clusters (30)-PAT甲级真题(并查集)

    题意:有n个人,每个人有k个爱好,如果两个人有某个爱好相同,他们就处于同一个集合.问总共有多少个集合,以及每个集合有多少人,并按从大到小输出. 很明显,采用并查集.vis[k]标记爱好k第一次出现的人 ...

  4. 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 = ...

  5. 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)\).这就相当于 ...

  6. [题解] Atcoder ABC 225 H Social Distance 2 生成函数,分治FFT

    题目 首先还没有安排座位的\(m-k\)个人之间是有顺序的,所以先把答案乘上\((m-k)!\),就可以把这些人看作不可区分的. 已经确定的k个人把所有座位分成了k+1段.对于第i段,如果我们能求出这 ...

  7. PAT甲级题解(慢慢刷中)

    博主欢迎转载,但请给出本文链接,我尊重你,你尊重我,谢谢~http://www.cnblogs.com/chenxiwenruo/p/6102219.html特别不喜欢那些随便转载别人的原创文章又不给 ...

  8. Tarjan & LCA 套题题目题解

    刷题之前来几套LCA的末班 对于题目 HDU 2586 How far away 2份在线模板第一份倍增,倍增还是比较好理解的 #include <map> #include <se ...

  9. 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)     ...

随机推荐

  1. c++自定义时间输出

    #include <time.h> time_t timep; struct tm *p; time(&timep); p=localtime(&timep); int l ...

  2. c语言1作业07

    这个作业属于那个课程 C语言程序设计II 这个作业要求在哪里 https://edu.cnblogs.com/campus/zswxy/CST2019-4/homework/9932 我在这个课程的目 ...

  3. HDU 1159 Common Subsequence (动态规划、最长公共子序列)

    Common Subsequence Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Other ...

  4. cpu和内存的使用率统计

    统计cpu和内存一个月的平均使用率: #!/bin/bash totalcpu_rate=0.0 totalmem_rate=0.0 num_days=$(ls -l /var/log/sa/sa[0 ...

  5. Luogu P4602 [CTSC2018]混合果汁

    题目 把果汁按美味度降序排序,以单价为下标插入主席树,记录每个节点的\(sum\)果汁升数和\(val\)果汁总价. 每次询问二分最小美味度,查询美味度大于等于\(mid\)的总体积为\(L\)的最低 ...

  6. git diff 命令用法

    理解git diff的前提,首先要理解git中工作区,暂存区,本地版本库的概念,如果头脑中有这些概念,接着往下读. git diff test.c 用来查看工作区和暂存区中test.c文件的区别. g ...

  7. filebeat->redis->logstash->elasticsearch->kibana

    整体流程 filebeat收集openresty应用日志传输到Redis集群中 Logstash从Redis集群中拉取数据,并传输到Elasticsearch集群 使用Kibana可视化索引 使用El ...

  8. Homebrew学习(二)之安装、卸载、更新

    安装 1.网上的安装方法都是用curl,从官网找到命令复制到终端,然后回车,结果报错请求超时 /usr/bin/ruby -e "$(curl -fsSL https://raw.githu ...

  9. BZOJ 3118 Orz the MST

    权限题qwq 如果我们要使得某棵生成树为最小生成树,那么上面的边都不能被替代,具体的,对于一个非树边,它的权值要\(\ge\)它两端点在树上的路径上的所以边的权值,所以对于每个非树边就可以对一些树边列 ...

  10. 六、while循环

    案例1: do while 循环  很少用到. for循环和while循环用的最多.