总得来说
最大生成树
维护四个域,从U到LCA的最大值,最小值,从U到LCA的最优值,从LCA到U的最优值
Tarjan离线处理
在处理并查集的时候维护四个域,必须要先维护上面的点,再维护下面的点
如果查询的终点是已经访问过的点,直接连接至LCA
然后全部遍历完了之后再维护并查集LCA
// whn6325689
// Mr.Phoebe
// http://blog.csdn.net/u013007900
#include <algorithm>
#include <iostream>
#include <iomanip>
#include <cstring>
#include <climits>
#include <complex>
#include <fstream>
#include <cassert>
#include <cstdio>
#include <bitset>
#include <vector>
#include <deque>
#include <queue>
#include <stack>
#include <ctime>
#include <set>
#include <map>
#include <cmath>
#include <functional>
#include <numeric>
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
typedef long long ll;
typedef long double ld;
typedef pair<ll, ll> pll;
typedef complex<ld> point;
typedef pair<int, int> pii;
typedef pair<pii, int> piii;
typedef vector<int> vi;
#define CLR(x,y) memset(x,y,sizeof(x))
#define mp(x,y) make_pair(x,y)
#define pb(x) push_back(x)
#define lowbit(x) (x&(-x))
#define MID(x,y) (x+((y-x)>>1))
#define speed std::ios::sync_with_stdio(false);
#define eps 1e-9
#define PI acos(-1.0)
#define INF 0x3f3f3f3f
#define LLINF 1LL<<62
template<class T>
inline bool read(T &n)
{
T x = 0, tmp = 1;
char c = getchar();
while((c < '0' || c > '9') && c != '-' && c != EOF) c = getchar();
if(c == EOF) return false;
if(c == '-') c = getchar(), tmp = -1;
while(c >= '0' && c <= '9') x *= 10, x += (c - '0'),c = getchar();
n = x*tmp;
return true;
}
template <class T>
inline void write(T n)
{
if(n < 0)
{
putchar('-');
n = -n;
}
int len = 0,data[20];
while(n)
{
data[len++] = n%10;
n /= 10;
}
if(!len) data[len++] = 0;
while(len--) putchar(data[len]+48);
}
//-----------------------------------
const int MAXN=50010;
struct edge
{
int u,v,w;
bool operator < (const edge & b) const{return w>b.w;}
}ee[MAXN<<1];
struct Edge
{
int to,next;
}e[MAXN<<1],lca[MAXN<<1];
struct query
{
int u,v,next;
int id;
}q[MAXN<<1];
int h[MAXN],qh[MAXN],lh[MAXN];
int vis[MAXN],ma[MAXN],mi[MAXN],up[MAXN],down[MAXN];
int n,m,qq,tot,cnt,num,ans[MAXN],angry[MAXN];
void update(int u,int v);
struct disjoint
{
int fa[MAXN];
void init(int n)
{
for(int i=0;i<=n;i++)
fa[i]=i;
}
int find_fa(int u)
{
return (u == fa[u]) ? fa[u] : (fa[u] = find_fa(fa[u]));
}
int find(int u)
{
if(u==fa[u]) return fa[u];
int v=fa[u];
fa[u]=find(fa[u]);
update(u,v);
return fa[u];
}
void merge(int u,int v)
{
fa[u]=v;
}
}st;
void init(int n)
{
CLR(h,-1);CLR(qh,-1);CLR(lh,-1);CLR(vis,0);
tot=cnt=num=0;
st.init(n);
}
void update(int u,int v) //更新四个域
{
//cout<<"fa:"<<u<<" "<<v<<endl;
up[u]=max(ma[v]-mi[u],max(up[u],up[v]));
down[u]=max(ma[u]-mi[v],max(down[u],down[v]));
ma[u]=max(ma[u],ma[v]);
mi[u]=min(mi[u],mi[v]);
}
void addedge(int u,int v)
{
e[tot].to=v;
e[tot].next=h[u];
h[u]=tot++;
}
void addquery(int u,int v,int w)
{
q[cnt].u=u;
q[cnt].v=v;
q[cnt].id=w;
q[cnt].next=qh[u];
qh[u]=cnt++;
}
void Kruskal()
{
sort(ee,ee+m);
int sum=0;
for(int i=0;i<m;i++)
{
int u=st.find_fa(ee[i].u);
int v=st.find_fa(ee[i].v);
if(u!=v)
{
st.merge(v,u);
sum+=ee[i].w;
addedge(ee[i].u,ee[i].v);addedge(ee[i].v,ee[i].u);
//cout<<ee[i].u<<" "<<ee[i].v<<endl;
}
}
write(sum),putchar('\n');
}
void dfs(int u)
{
vis[u]=1;
for(int i=qh[u];~i;i=q[i].next) //已经计算过的子树中的点的LCA
{
if(vis[q[i].v])
{
int xx=st.find(q[i].v);
lca[num].to=i; //如果是偶数则是顺,奇数逆
lca[num].next=lh[xx];
lh[xx]=num++;
}
}
for(int i=h[u];~i;i=e[i].next)
{
if(vis[e[i].to]) continue;
dfs(e[i].to);
st.merge(e[i].to,u); //位置高的为father
}
for(int i=lh[u];~i;i=lca[i].next)
{
int j=lca[i].to;
int u=q[j].u,v=q[j].v;
st.find(u);//st.find(v);
if(j&1) //如果是偶数则是顺,奇数逆
swap(u,v);
ans[q[j].id]=max(ma[v]-mi[u],max(up[u],down[v]));// 从u->v
//cout<<q[j].id<<" "<<ans[q[j].id]<<endl;
}
}
int main()
{
//freopen("data.txt","r",stdin);
//freopen("w.txt","w",stdout);
while(read(n))
{
init(n);
for(int i=1;i<=n;i++)
{
read(angry[i]);
ma[i]=mi[i]=angry[i];
up[i]=down[i]=0;
}
read(m);
for(int i=0;i<m;i++)
read(ee[i].u),read(ee[i].v),read(ee[i].w);
read(qq);
for(int i=0,u,v;i<qq;i++)
{
read(u),read(v);
addquery(u,v,i);addquery(v,u,i);
}
Kruskal();
st.init(n);
dfs(1);
for(int i=0;i<qq;i++)
write(ans[i]),putchar('\n');
}
return 0;
}
用倍增求LCA的方法在线求
#include <bits/stdc++.h>
struct node {
int from, to, cost;
bool operator < (const node &rhs) const {
return cost > rhs.cost;
}
};
node edge[50010];
int fa[50010];
int find(int x) {
return fa[x] == x ? x : fa[x] = find(fa[x]);
}
int to[50010<<1], pre[50010<<1], tail[50010];
int e_tot = 0;
inline void add(int _from, int _to) {
to[e_tot] = _to;
pre[e_tot] = tail[_from];
tail[_from] = e_tot++;
}
void getEdge(int n) {
for(int i = 1; i <= n; ++i)
fa[i] = i;
int m;
scanf("%d", &m);
for(int i = 0; i < m; ++i)
scanf("%d%d%d", &edge[i].from, &edge[i].to, &edge[i].cost);
std::sort(edge, edge + m);
long long ans = 0;
e_tot = 0;
memset(tail, -1, sizeof tail);
for(int i = 0; i < m; ++i) {
int pu = find(edge[i].from), pv = find(edge[i].to);
if(pu != pv) {
add(edge[i].from, edge[i].to);
add(edge[i].to, edge[i].from);
ans += edge[i].cost;
fa[pu] = pv;
}
}
printf("%lld\n", ans);
}
int min[50010][17], max[50010][17], ansFromU[50010][17], ansToU[50010][17], p[50010][17], dep[50010];
int value[50010];
void dfs(int now, int father, int depth) {
memset(min[now], 0x3f, sizeof min[now]);
memset(max[now], 0, sizeof max[now]);
p[now][0] = father;
min[now][0] = std::min(value[now], value[p[now][0]]);
max[now][0] = std::max(value[now], value[p[now][0]]);
ansFromU[now][0] = value[now] > value[p[now][0]] ? value[now] - value[p[now][0]] : 0;
ansToU[now][0] = value[now] < value[p[now][0]] ? value[p[now][0]] - value[now] : 0;
dep[now] = depth;
for(int i = 1; i < 17; ++i) {
p[now][i] = p[p[now][i-1]][i-1];
min[now][i] = std::min(min[now][i-1], min[p[now][i-1]][i-1]);
max[now][i] = std::max(max[now][i-1], max[p[now][i-1]][i-1]);
ansFromU[now][i] = std::max(ansFromU[now][i-1], ansFromU[p[now][i-1]][i-1]);
ansFromU[now][i] = std::max(ansFromU[now][i], max[now][i-1] - min[p[now][i-1]][i-1]);
ansToU[now][i] = std::max(ansToU[now][i-1], ansToU[p[now][i-1]][i-1]);
ansToU[now][i] = std::max(ansToU[now][i], max[p[now][i-1]][i-1] - min[now][i-1]);
}
for(int i = tail[now]; i != -1; i = pre[i]) {
if(to[i] == p[now][0])
continue;
dfs(to[i], now, depth + 1);
}
}
int getLca(int u, int v) {
if(dep[u] > dep[v])
std::swap(u, v);
for(int delta = dep[v] - dep[u], i = 0; delta; delta >>= 1, ++i) {
if(delta & 1)
v = p[v][i];
}
if(u == v)
return u;
for(int i = 17 - 1; i >= 0; --i) {
if(p[u][i] == p[v][i])
continue;
u = p[u][i], v = p[v][i];
}
return p[u][0];
}
int getFromU(int u, int lca) {
int maxPre = 0, ans = 0;
for(int delta = dep[u] - dep[lca], i = 0; delta; delta >>= 1, ++i) {
if(delta & 1) {
ans = std::max(ans, ansFromU[u][i]);
ans = std::max(ans, maxPre - min[u][i]);
maxPre = std::max(maxPre, max[u][i]);
u = p[u][i];
}
}
return ans;
}
int getToU(int u, int lca) {
int minPre = 0x3f3f3f3f, ans = 0;
for(int delta = dep[u] - dep[lca], i = 0; delta; delta >>= 1, ++i) {
if(delta & 1) {
ans = std::max(ans, ansToU[u][i]);
ans = std::max(ans, max[u][i] - minPre);
minPre = std::min(minPre, min[u][i]);
u = p[u][i];
}
}
return ans;
}
int getMax(int u, int lca) {
int ret = 0;
for(int delta = dep[u] - dep[lca], i = 0; delta; delta >>= 1, ++i) {
if(delta & 1) {
ret = std::max(ret, max[u][i]);
u = p[u][i];
}
}
return ret;
}
int getMin(int u, int lca) {
int ret = 0x3f3f3f3f;
for(int delta = dep[u] - dep[lca], i = 0; delta; delta >>= 1, ++i) {
if(delta & 1) {
ret = std::min(ret, min[u][i]);
u = p[u][i];
}
}
return ret;
}
void MAIN(int n) {
for(int i = 1; i <= n; ++i)
scanf("%d", &value[i]);
getEdge(n);
dfs(1, 1, 0);
int q;
scanf("%d", &q);
for(int i = 0, u, v; i < q; ++i) {
scanf("%d%d", &u, &v);
int ans = 0, lca = getLca(u, v);
ans = std::max(ans, getToU(u, lca));
ans = std::max(ans, getFromU(v, lca));
ans = std::max(ans, getMax(v, lca) - getMin(u, lca));
printf("%d\n", ans);
}
}
int main() {
int n;
while(scanf("%d", &n) > 0)
MAIN(n);
return 0;
}
树链剖分+线段树
#include <iostream>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <string>
#include <cstdio>
#include <vector>
#include <climits>
using namespace std;
#define lson(x) (x<<1)
#define rson(x) (x<<1|1)
#define pb push_back
const int MAXN=33333;
struct Node{
int l,r,Min,Max,Pro[2];
}node[MAXN*6];
int f[MAXN];
int n,m;
int head[MAXN],tot;
int top[MAXN];
int fa[MAXN];
int deep[MAXN];
int num[MAXN];
int p[MAXN];
int fp[MAXN];
int son[MAXN];
int pos;
struct Seg{
void pushup(int x){
node[x].Max=max(node[lson(x)].Max, node[rson(x)].Max );
node[x].Min=min(node[lson(x)].Min, node[rson(x)].Min );
node[x].Pro[1]=max(node[lson(x)].Pro[1], node[rson(x)].Pro[1] );
node[x].Pro[1]=max(node[x].Pro[1] , node[rson(x)].Max-node[lson(x)].Min );///maybe negative!!!!
node[x].Pro[0]=max(node[lson(x)].Pro[0], node[rson(x)].Pro[0] );
node[x].Pro[0]=max(node[x].Pro[0] , node[lson(x)].Max-node[rson(x)].Min );///maybe negative!!!!
}
void build(int l,int r,int x=1){
node[x].l=l ; node[x].r=r;
if(l==r){
node[x].Max=f[fp[l]];///mind f
node[x].Min=f[fp[l]];///mind f
//cout<<l<<":"<<f[fp[l]]<<endl;
node[x].Pro[0]=0;
node[x].Pro[1]=0;
return ;
}
int mid=(l+r)/2;
build(l,mid,lson(x));
build(mid+1,r,rson(x));
pushup(x);
}
int query(int l,int r,int flag,int x=1 ){///mind !
if(l==r) return 0;
if(node[x].l >= l && node[x].r <= r){
return node[x].Pro[flag];
}
int mid=(node[x].l + node[x].r)/2;
//pushdown
int ans=-INT_MAX; ///is right?
if(l<=mid){
ans=max(ans, query(l,r ,flag,lson(x)) );
}
if(r>mid) {
ans=max(ans,query(l,r, flag,rson(x) ) );
}
if(l<=mid && r>mid){
if(flag==1){
int lMin=queryMin(l,r,lson(x)) , rMax= queryMax(l,r,rson(x));
ans=max(ans, rMax-lMin);
}else{
int lMax=queryMax(l,r,lson(x)) , rMin= queryMin(l,r,rson(x));
ans=max(ans, lMax-rMin);
}
}
pushup(x);
return ans;
}
int queryMax(int l,int r,int x=1){///mind !
if(node[x].l >= l && node[x].r <= r){
return node[x].Max;
}
int mid=(node[x].l + node[x].r)/2;
//pushdown
int ans=-INT_MAX; ///is right?
if(l<=mid) ans=max(ans, queryMax(l,r,lson(x) ) );
if(r>mid) ans=max(ans,queryMax(l,r,rson(x) ) );
pushup(x);
return ans;
}
int queryMin(int l,int r,int x=1){///mind !
if(node[x].l >= l && node[x].r <= r){
return node[x].Min;
}
int mid=(node[x].l + node[x].r)/2;
//pushdown
int ans=INT_MAX; ///is right?
if(l<=mid) ans=min(ans, queryMin(l,r,lson(x) ) );
if(r>mid) ans=min(ans,queryMin(l,r,rson(x) ) );
pushup(x);
return ans;
}
}seg;
struct Edge{
int from,to,next , w;
}edge[MAXN*5] ;
void init(){
tot=0;
memset(head,-1,sizeof(head));
pos=1;
memset(son,-1,sizeof(son));
}
void addedge(int u,int v,int w){
edge[tot].from = u;
edge[tot].to = v;
edge[tot].w = w;
edge[tot].next = head[u];
head[u] = tot++;
}
void dfs1(int u,int pre,int d){
deep[u]=d;
fa[u]=pre;
num[u]=1;
for(int i=head[u];i != -1; i=edge[i].next){
int v=edge[i].to;
if(v!=pre){
dfs1(v,u,d+1);
num[u]+=num[v];
if(son[u] == -1 || num[v] > num[ son[u] ] )
son[u]=v;
}
}
}
void getpos(int u,int sp){
top[u]=sp;
p[u]=pos++;
fp[p[u]] = u;
if(son[u]==-1) return;
getpos(son[u] , sp);
for(int i=head[u] ; i!=-1 ; i=edge[i].next){
int v=edge[i].to;
if(v!=son[u] && v!=fa[u])
getpos(v,v);
}
}
int GetQ(int u,int v){
int f1=top[u] , f2=top[v];
int tmp=0;
vector<int > ANS ;
vector<int >MAX[2] ,MIN[2];
int flag=0;
while(f1!=f2){
if(deep[f1] < deep[f2]){
swap(f1,f2);
swap(u,v);
flag^=1;
}
int ans=seg.query(p[f1],p[u] , flag ) ;
ANS.push_back(ans);
MAX[flag].push_back(seg.queryMax(p[f1],p[u]) );
MIN[flag].push_back(seg.queryMin(p[f1],p[u]) );
u=fa[f1];
f1=top[u];
}
if(deep[u] > deep[v] ) swap(u,v) ;
else flag^=1;
int ans=seg.query(p[u], p[v] ,flag) ;
//cout<<p[u]<<" "<<p[v]<<" "<<flag<<endl;
ANS.push_back(ans);
if(ANS.size()==1) return ANS[0];
MAX[flag].push_back(seg.queryMax(p[u], p[v]) );
MIN[flag].push_back(seg.queryMin(p[u], p[v]) );
int lastres=ANS[0];
for(int i=MAX[1].size()-1 ; i>=0 ; i--){
MAX[0].pb(MAX[1][i]);
MIN[0].pb(MIN[1][i]);
}
int minn=MIN[0][0];
for(int i=1; i<ANS.size() ; i++){
lastres=max(lastres,ANS[i]);
lastres=max(lastres,MAX[0][i]-minn);
minn=min(minn,MIN[0][i]);
}
return lastres;
}
struct Bing{
int par[MAXN];
void init(int n){
for(int i=1;i<=n;i++) par[i]=i;
}
int find(int u){
if(par[u]==u) return u;
else return par[u]=find(par[u]);
}
void unite(int u,int v){
u=find(u);
v=find(v);
if(u==v) return;
par[u]=v;
}
}bing;
bool cmp(const Edge& e1,const Edge& e2){
return e1.w < e2.w;
}
int kruskal(int edgeNum , vector<pair<int ,int > >& newG ){
sort(edge,edge+edgeNum,cmp);
bing.init(n);
int res=0;
for(int i=0;i<edgeNum;i++){
Edge e=edge[i];
if(bing.find(e.from ) != bing.find(e.to ) ){
bing.unite(e.from , e.to);
newG.push_back(make_pair(e.from, e.to) );
res+=e.w;
}
}
return res;
}
int main()///mind lld??
{
//freopen("in.txt","r",stdin);
while(scanf("%d",&n)==1)
{
init();
for(int i=1;i<=n;i++) scanf("%d",&f[i]);
scanf("%d",&m);
for(int i=1;i<=m;i++){
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
w=-w;
addedge(u,v,w);
addedge(v,u,w);
}
vector<pair<int ,int > > newG;
int sum=kruskal(tot,newG);
sum=-sum;
printf("%d\n",sum);
tot=0;
memset(head,-1,sizeof(head));
for(int i=0;i<newG.size(); i++){
int u=newG[i].first ,v=newG[i].second;
addedge(u,v,0);
addedge(v,u,0);
}
dfs1(1,0,0);
getpos(1,1);
seg.build(1,pos-1);
//cout<<seg.query(5,6,0)<<endl;
int que;
scanf("%d",&que);
while(que--){
int u,v;
scanf("%d%d",&u,&v);
int ans=GetQ(u,v);
printf("%d\n",ans);
}
}
return 0;
}