题目链接:ZOJ 3649 Social Net
Problem
There are  individuals  . 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  .
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  . We have  operations : Person  wants to contact person , 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 . Here  means the angry value of the th people in the sequence.
We attempt to find the maximum  .
Example:
The sequence is 3(X), 4, 5, 6, 7, 5, 9, 4, 11(Y). The maximum  is 11-3=8.
The sequence is 3(X), 4, 5, 6, 7, 5, 9, 2, 11(Y). The maximum  is 11-2=9.
The sequence is 3(X), 10, 2, 5(Y). The maximum  is 10-3=7.
Input
The input contains multiple test cases. Each test case begins with a line containing a single integer . The following line contains  integers .
The subsequent line describe the number of relations  . The next  lines contain the information about relations: , , . Their friendship value is .
Afterward gives . The next  lines contain the operations: , . person  wants to contact person .
Output
For each case, print maximum sum of friendship value of the net on the first line.
The next  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
Translation
题目意思抽象出来是:给你 个点的一张图,先求最大生成树,然后在树里给出一大堆询问,对于每对询问给出两个参数 ,问你树上这两点之间最短路上 的最大值,其中要保证 。
Analysis
第一问求最大生成树果断的 Kruskal,不用讲了……
第二问,如果直接问我们路径上 的最大值,很显然可以用树上倍增解决,但是麻烦之处就在于这个 。这可怎么办呢?
我们可以用一个分治的思想:如果把 到 的路径看成一个数列,那么我们可以从中间割开,左右分别处理出答案,然后最终答案就是这个数列里右边的最大值和左边的最小值之差,和左右答案取个 max。
那么我们自然想到了:维护五个树上倍增数组:
- 
表示从 点向上推 个单位的点;
 - 
表示从 点向上推 个单位的距离内 的最大值;
 
什么叫“反向差值”呢?根据 ,“正向差值”是指对于 的差值,“反向差值” 则是对于 的差值。
其实思路清晰,写起来并不算麻烦。
Code
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=30005,maxm=60005,maxe=50005;
int n,m,q,w[maxn],fa[maxn],deep[maxn],sum=0;
int tot=0,lnk[maxn],nxt[maxm],son[maxm];
int f[maxn][20],max_num[maxn][20],min_num[maxn][20],dif_upd[maxn][20],dif_dwn[maxn][20];
bool vis[maxn];
struct Edge{
    int x,y,w;
}e[maxe];
inline int max3(int x,int y,int z){
    return z>max(x,y)?z:max(x,y);
}
inline bool Compare(Edge a,Edge b){
    return a.w>b.w;
}
inline int read(){
    int ret=0,f=1; ch=();
     (ch<||ch>) { (ch==) f=;ch=();}
     (ch>=&&ch<=) ret=ret*+ch-,ch=();
     ret*f;
}
{
     x<?-x:x;
}
{
    tot++;son[tot]=y;nxt[tot]=lnk[x];lnk[x]=tot;
}
{
    (w,,(w));
    (fa,,(fa));
    (deep,,(deep));
    (f,,(f));
    (max_num,,(max_num));
    (min_num,,(min_num));
    (dif_upd,,(dif_upd));
    (dif_dwn,,(dif_dwn));
    tot=;sum=;
    (lnk,,(lnk));
    (nxt,,(nxt));
    (son,,(son));
    (vis,,(vis));
    (e,,(e));
}
{
     (fa[x]==x)  x;
    fa[x]=(fa[x]);
     fa[x];
}
{
    (e,e+m,Compare);
     ( i=;i<=n;i++) fa[i]=i;
     cnt=;
     ( i=;i<=m&&cnt<n;i++){
         fx=(e[i].x),fy=(e[i].y);
         (fx==fy) ;
        sum+=e[i].w;
        (e[i].x,e[i].y);(e[i].y,e[i].x);
        fa[fx]=fy;cnt++;
    }
     (cnt!=n) ();
}
{
    vis[x]=;
     ( i=lnk[x];i;i=nxt[i])  (!vis[son[i]]){
        fa[son[i]]=x;
        deep[son[i]]=deep[x];
        (son[i]);
    }
}
{
     ( i=;i<=n;i++){
        f[i][]=fa[i];
        max_num[i][]=(w[i],w[fa[i]]);
        min_num[i][]=(w[i],w[fa[i]]);
        dif_upd[i][]=w[fa[i]]-w[i];dif_dwn[i][]=w[i]-w[fa[i]];
    }
     ( j=;j<;j++)
         ( i=;i<=n;i++){
            f[i][j]=f[f[i][j]][j];
            max_num[i][j]=(max_num[i][j],max_num[f[i][j]][j]);
            min_num[i][j]=(min_num[i][j],min_num[f[i][j]][j]);
            dif_upd[i][j]=(dif_upd[i][j],dif_upd[f[i][j]][j],max_num[f[i][j]][j]-min_num[i][j]);
            dif_dwn[i][j]=(dif_dwn[i][j],dif_dwn[f[i][j]][j],max_num[i][j]-min_num[f[i][j]][j]);
        }
    
    
    
    
    
    
    
    
    
}
{
     ret=;
     now_min=,now_max=;
     (x==y)  ;
     ( i=;i>=;i--)  (deep[f[x][i]]>=deep[y]){
        ret=(ret, max_num[x][i]-now_min, dif_upd[x][i]);
        now_min=(now_min,min_num[x][i]);
        x=f[x][i];
    }
     ( i=;i>=;i--)  (deep[f[y][i]]>=deep[x]){
        ret=(ret, now_max-min_num[y][i], dif_dwn[y][i]);
        now_max=(now_max,max_num[y][i]);
        y=f[y][i];
    }
     (x==y)  ret;
     ( i=;i>=;i--)  (f[x][i]!=f[y][i]){
        ret=(ret,dif_upd[x][i],dif_dwn[y][i]);
        ret=(ret,max_num[x][i]-now_min,now_max-min_num[y][i]);
        now_min=(now_min,min_num[x][i]);
        now_max=(now_max,max_num[y][i]);
        x=f[x][i];y=f[y][i];
    }
    ret=(ret,dif_upd[x][],dif_dwn[y][]);
    ret=(ret,max_num[x][]-now_min,now_max-min_num[y][]);
    now_min=(now_min,min_num[x][]);
    now_max=(now_max,max_num[y][]);
    ret=(ret,now_max-now_min);
     ret;
}
{
     ((,&n)!=){
        ();
         ( i=;i<=n;i++) w[i]=(),fa[i]=i;
        m=();
         ( i=;i<=m;i++) e[i].x=(),e[i].y=(),e[i].w=();
        ();(,sum);
        (fa,,(fa));
        deep[]=;();
        
        
        ();
        q=();
         ( i=;i<=q;i++){
             x=(),y=();
            (,(x,y));
        }
    }
     ;
}