There are n individuals(2 <= n <= 30000). Everyone has one or more friends. And everyone can contact all people by friend-relation. If two persons aren't friends, they also can contact by their friends. Each pair of friends have a friendship value ai(1 <= ai <= 50000).
Firstly, you will relieve some friend-relation. The rest of the friend-relation is the social net. The net is unique in all test cases. In this net, everyone can contact all people by rest friend-relation. The net has a minimum number of friend-relation. And the net has maximum sum of friendship value. We want to get the maximum sum.
Secondly, everyone has an angry value bi(1 <= bi <= 100000). We have q operations(1 <= q <= 30000): Person X wants to contact person Y, this operation merely has one sequence which describes the process. The sequence consists of persons' angry value. The persons are on the process.
We suppose the sequence is c1, c2, c3, ... ,ci. Here ci means the angry value of the ith people in the sequence.
We attempt to find the maximum ck-cj (ck >= cj, j <= k).
Example:
The sequence is 3(X), 4, 5, 6, 7, 5, 9, 4, 11(Y). The maximum ck-cj is 11-3=8.
The sequence is 3(X), 4, 5, 6, 7, 5, 9, 2, 11(Y). The maximum ck-cj is 11-2=9.
The sequence is 3(X), 10, 2, 5(Y). The maximum ck-cj is 10-3=7.
Input
The input contains multiple test cases. Each test case begins with a line containing a single integer n. The following line contains n integers bi.
The subsequent line describe the number of relations m(n <= m <= 50000). The next m lines contain the information about relations: x, y, ai. Their friendship value is ai.
Afterward gives q. The next q lines contain the operations: x, y. person X wants to contact person Y.
Output
For each case, print maximum sum of friendship value of the net on the first line.
The next q lines contain the answers of every operations.
Sample Input
6 3 5 1 7 3 5 7 1 2 5 1 3 6 2 4 7 2 5 8 3 6 9 4 5 1 5 6 2 5 6 1 6 2 6 3 6 4 6 5
Sample Output
35 2 4 0 6 4
题意:首先构建一个最大生成树,然后会有若干个询问(a,b),问从a到b中最大的ci-cj 。
思路:我们用Kruskal 构建一个最大生成树,然后建好树后,就建立rmq,其中需要知道某一段的最大值最小值,要知道某一段的最大的差值(就是询问那个值),其中一个是父亲减子孙的,还要一个是子孙减父亲的。询问的时候就不多说了看代码吧。
代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string.h>
using namespace std;
const int maxn = 30000 + 5;
#pragma comment(linker,"/STACK:1024000000,1024000000")
int n, m, Q;
int maxv[maxn][16];
int minv[maxn][16];
int maxdiff[maxn][16];
int diff_reverse[maxn][16];
int anc[maxn][16];
int L[maxn];
int c[maxn], p[maxn];
int find(int x)
{
if (x == p[x]) return x;
return p[x] = find(p[x]);
}
inline int max(int a, int b) { return a > b ? a : b; }
inline int min(int a, int b) { return a < b ? a : b; }
struct Edge
{
int u, v, w;
bool operator<(const Edge&e)const
{
return w >e.w;
}
}edges[50000+5];
struct Node
{
int v;
Node*next;
}*first[maxn],adj[maxn*2];
int ptr;
void add(int u, int v)
{
adj[++ptr].v = v;
adj[ptr].next = first[u];
first[u] = &adj[ptr];
}
void input()
{
for (int i = 1; i <= n; ++i) scanf("%d", c + i);
scanf("%d", &m);
for (int i = 0; i < m; ++i) scanf("%d%d%d", &edges[i].u, &edges[i].v, &edges[i].w);
sort(edges, edges + m);
for (int i = 1; i <= n; ++i) p[i] = i;
int rest = n-1;
int sum = 0;
memset(first, 0, sizeof(first)); ptr = 0;
for (int i = 0; i < m && rest; ++i) {
int u = find(edges[i].u), v = find(edges[i].v);
if (u == v) continue;
--rest;
p[u] = v;
sum += edges[i].w;
add(edges[i].u, edges[i].v);
add(edges[i].v, edges[i].u);
}
printf("%d\n", sum);
}
void buildtree(int u,int fa)
{
anc[u][0] = fa;
maxv[u][0] = minv[u][0] = c[u];
for (Node*p = first[u]; p; p = p->next){
int v = p->v;
if (v == fa) continue;
L[v] = L[u] + 1;
buildtree(v, u);
}
}
void rmq()
{
for (int j = 1; j < 16; ++j) {
for (int i = 1; i <= n; ++i) {
int a = anc[i][j - 1];
if (a == -1) continue;
anc[i][j] = anc[a][j - 1];
maxv[i][j] = max(maxv[a][j - 1], maxv[i][j - 1]);
minv[i][j] = min(minv[i][j - 1], minv[a][j - 1]);
maxdiff[i][j] = max(maxdiff[i][j - 1], maxdiff[a][j - 1]);
maxdiff[i][j] = max(maxdiff[i][j], maxv[a][j - 1] - minv[i][j - 1]);
diff_reverse[i][j] = max(diff_reverse[i][j - 1], max(diff_reverse[a][j - 1], maxv[i][j - 1] - minv[a][j - 1]));
}
}
}
int query(int a, int b)
{
if (a == b) return 0;
int maxL = max(L[a], L[b]);
int ret = -1;
int l_min = c[a], r_max = c[b];
int k;
for (k = 0; (1 << k) <= maxL; ++k); --k;
if (L[a] > L[b]) {
for (int j = k; j >= 0;--j)
if (L[a] - (1 << j) >= L[b]) {
ret = max(ret, max(maxv[a][j]-l_min,maxdiff[a][j]));
l_min = min(l_min,minv[a][j]);
a = anc[a][j];
}
}
else if (L[a] < L[b]) {
for (int j = k; j >= 0;--j)
if (L[b] - (1 << j) >= L[a]) {
ret = max(ret, max(r_max-minv[b][j],diff_reverse[b][j]));
r_max = max(r_max,maxv[b][j]);
b = anc[b][j];
}
}
if (a == b) return max(ret, r_max - l_min);
for (int j = k; j >= 0;--j)
if (anc[a][j] != -1 && anc[a][j] != anc[b][j])
{
int l_val = max(maxdiff[a][j], maxv[a][j] - l_min);
int r_val = max(diff_reverse[b][j], r_max - minv[b][j]);
ret = max(ret, max(l_val, r_val));
l_min = min(l_min, minv[a][j]);
r_max = max(r_max, maxv[b][j]);
a = anc[a][j], b = anc[b][j];
}
int l_val = max(maxdiff[a][0], maxv[a][0] - l_min);
int r_val = max(diff_reverse[b][0], r_max - minv[b][0]);
ret = max(ret, max(l_val, r_val));
l_min = min(l_min, minv[a][0]);
r_max = max(r_max, maxv[b][0]);
int lca = anc[a][0];
r_max = max(r_max, c[lca]), l_min = min(l_min, c[lca]);
return max(ret,max(0,r_max-l_min));
}
void solve()
{
scanf("%d", &Q);
while (Q--) {
int u, v; scanf("%d%d", &u, &v);
printf("%d\n", query(u, v));
}
}
int main()
{
while (scanf("%d", &n) == 1)
{
input();
memset(anc, -1, sizeof(anc));
memset(maxv, -1, sizeof(maxv));
memset(minv, 0x3f, sizeof(minv));
memset(maxdiff, 0, sizeof(maxdiff));
memset(diff_reverse, 0, sizeof(diff_reverse));
L[1] = 0;
buildtree(1,-1);
rmq();
solve();
}
}