牛逼题,第一步转化都想不到。
首先题目要求的是选出两条路径\((x_1,y_1),(x_2,y_2)\)满足有交,并且并的部分减去\(w_1+w_2\)最大。
不妨假设\(p_1\)是\(x_1\)与\(x_2\)的LCA,并且是路径交离\(x_1\)和\(x_2\)最近的一点,\(p_2\)是\(y_1\)和\(y_2\)的LCA,并且是路径交离\(x_1\)和\(x_2\)最近的一点,则这个权值的两倍等于\(dist(x_1,y_1)+dist(x_2,y_2)+dist(x_1,x_2)+dist(y_1,y_2)-2w_1-2w_2\)。
考虑枚举\(p_1\),然后这个权值变为\(dist(x_1,y_1)+dist(x_2,y_2)+d_{x_1}+d_{x_2}-2d_{p_1}+dist(y_1,y_2)-2w_1-2w_2\)。
将\(dist(x_1,y_1)+d_{x_1}-2w_1\)看成\(y_1\)的点权,同样的东西看成\(y_2\)的点权,那么就是\(y_1\)到\(y_2\)的路径长度加上点权减去当前的\(2d_{p_1}\)。
维护这种最远点对显然可以只维护直径两个点,然后用欧拉序的LCA就可以做到\(O(1)\)合并。于是可以用线段树合并维护这个过程,在\([x_1,LCA(x_1,y_1))\)放下\(y_1\)这个点,在另一端上放下\(x_1\)这个点。记得删除就好了。合并的时候也可以计算答案。
时间复杂度\(O(\sum m\log m)\),真的很卡常,特别是一条链。
code:
#include<bits/stdc++.h>
#define Gc() getchar()
#define Me(x,y) memset(x,y,sizeof(x))
#define Mc(x,y) memcpy(x,y,sizeof(x))
#define d(x,y) ((m)*(x-1)+(y))
#define R(n) (rnd()%(n))
#define Pc(x) putchar(x)
#define LB lower_bound
#define UB upper_bound
#define PB push_back
using ll=long long;using db=double;using lb=long db;using ui=unsigned;using ull=unsigned ll;
using namespace std;const int N=5e4+5,M=1e7+5,K=1e6+5,mod=998244353,Mod=mod-1;const ll INF=1e18+7;const db eps=1e-5;mt19937 rnd(263082);
struct IO{
static const int S=1<<21;
char buf[S],*p1,*p2;int st[105],Top;
~IO(){clear();}
inline void clear(){fwrite(buf,1,Top,stdout);Top=0;}
inline void pc(const char c){Top==S&&(clear(),0);buf[Top++]=c;}
inline char gc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
inline IO&operator >> (char&x){while(x=gc(),x==' '||x=='\n'||x=='\r');return *this;}
template<typename T>inline IO&operator >> (T&x){
x=0;bool f=0;char ch=gc();
while(ch<'0'||ch>'9'){if(ch=='-') f^=1;ch=gc();}
while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=gc();
f?x=-x:0;return *this;
}
inline IO&operator << (const char c){pc(c);return *this;}
template<typename T>inline IO&operator << (T x){
if(x<0) pc('-'),x=-x;
do{st[++st[0]]=x%10,x/=10;}while(x);
while(st[0]) pc('0'+st[st[0]--]);return *this;
}
}fin,fout;
int n,m,k,x,y,Rt[N];ll W[N],z,Ans;
struct Edge{int to,w;};vector<Edge> S[N];
namespace ER{
int fa[N][20],lg[N*2],Id[20][N*2],Bg[N],Df[N*2],Dh;unsigned short d[N];
void Make(int x,int La){Me(fa[x],0);
Df[Bg[x]=++Dh]=x;d[x]=d[La]+1;fa[x][0]=La;for(int i=1;fa[x][i-1];i++) fa[x][i]=fa[fa[x][i-1]][i-1];
for(Edge i:S[x]) i.to^La&&(W[i.to]=W[x]+i.w,Make(i.to,x),Df[++Dh]=x);
}
void BD(){Dh=0;
int i,j;Make(1,0);for(i=2;i<=Dh;i++) lg[i]=lg[i/2]+1;
for(i=Dh;i;i--) for(Id[0][i]=Df[i],j=1;i+(1<<j)-1<=Dh;j++) Id[j][i]=(d[Id[j-1][i]]<d[Id[j-1][i+(1<<j-1)]]?Id[j-1][i]:Id[j-1][i+(1<<j-1)]);
}
int LCA(int x,int y){x=Bg[x];y=Bg[y];x>y&&(swap(x,y),0);int D=lg[y-x+1];return d[Id[D][x]]<d[Id[D][y-(1<<D)+1]]?Id[D][x]:Id[D][y-(1<<D)+1];}
ll Dt(int x,int y){return W[x]+W[y]-2*W[LCA(x,y)];}
int Jump(int x,int y){for(int i=lg[d[x]];~i;i--) d[fa[x][i]]>d[y]&&(x=fa[x][i]);return x;}
}
struct Node{int id;ll w;}C1;
struct Line{
Node A,B;ll W;
Line operator +(const Line &C)const{ll D[6],Mx;
if(!A.id&&!B.id) return C;if(!C.A.id&&!C.B.id) return (Line){A,B,W};
if(A.id&&B.id)D[0]=W;else D[0]=-INF;if(A.id&&C.A.id)D[1]=A.w+C.A.w+ER::Dt(A.id,C.A.id);else D[1]=-INF;
if(A.id&&C.B.id)D[2]=A.w+C.B.w+ER::Dt(A.id,C.B.id);else D[2]=-INF;if(B.id&&C.A.id)D[3]=B.w+C.A.w+ER::Dt(B.id,C.A.id);else D[3]=-INF;
if(B.id&&C.B.id) D[4]=B.w+C.B.w+ER::Dt(B.id,C.B.id);else D[4]=-INF;if(C.A.id&&C.B.id)D[5]=C.W;else D[5]=-INF;
Mx=max(max(D[0],D[1]),max(max(D[2],D[3]),max(D[4],D[5])));
if(D[0]==Mx) return (Line){A,B,W};if(D[1]==Mx) return (Line){A,C.A,D[1]};if(D[2]==Mx) return (Line){A,C.B,D[2]};
if(D[3]==Mx) return (Line){B,C.A,D[3]};if(D[4]==Mx) return (Line){B,C.B,D[4]};return C;
}
ll operator *(const Line &C)const{
ll Mx=-INF;if(A.id&&C.A.id) Mx=max(Mx,A.w+C.A.w+ER::Dt(A.id,C.A.id));
if(A.id&&C.B.id) Mx=max(Mx,A.w+C.B.w+ER::Dt(A.id,C.B.id));
if(B.id&&C.A.id) Mx=max(Mx,B.w+C.A.w+ER::Dt(B.id,C.A.id));
if(B.id&&C.B.id) Mx=max(Mx,B.w+C.B.w+ER::Dt(B.id,C.B.id));return Mx;
}
}C2;
namespace Tree{
Line f[M];int L[M],R[M],Ct;void Up(int v){f[v]=f[L[v]]+f[R[v]];}
void Cl(){for(int i=1;i<=Ct;i++) L[i]=R[i]=0,f[i]=C2;Ct=0;}
void Ins(int x,Line y,int &v,int l=1,int r=m){!v&&(v=++Ct);f[v]=f[v]+y;if(l==r)return;int Mi=l+r>>1;x<=Mi?Ins(x,y,L[v],l,Mi):Ins(x,y,R[v],Mi+1,r);}
void Del(int x,int &v,int l=1,int r=m){if(l==r) {v=0;return;}int Mi=l+r>>1;x<=Mi?Del(x,L[v],l,Mi):Del(x,R[v],Mi+1,r);Up(v);}
int Merge(int x,int y){if(!x||!y) return x|y;f[x]=f[x]+f[y];L[x]=Merge(L[x],L[y]);R[x]=Merge(R[x],R[y]);return x;}
}
struct Ques{int p;Node B;};vector<Ques> T[N];vector<int> D[N];
void GA(int x,int La){
Rt[x]=0;for(Ques i:T[x]) {
Line p=(Line){i.B,C1};Ans=max(Ans,p*Tree::f[Rt[x]]-2*W[x]);//cerr<<Ans<<' '<<x<<'\n';
Tree::Ins(i.p,p,Rt[x]);
}for(Edge i:S[x]) {
GA(i.to,x);Ans=max(Ans,Tree::f[Rt[x]]*Tree::f[Rt[i.to]]-2*W[x]);//cerr<<Ans<<' '<<x<<'\n';
Rt[x]=Tree::Merge(Rt[x],Rt[i.to]);
}
for(int i:D[x]) Tree::Del(i,Rt[x]);
}
void Solve(){
int i,j;for(i=1;i<=n;i++) S[i].clear(),T[i].clear(),D[i].clear();fin>>n;for(i=1;i<n;i++) fin>>x>>y>>z,S[x].PB((Edge){y,z});
ER::BD();
Tree::Cl();fin>>m;for(i=1;i<=m;i++){
fin>>x>>y>>z;int Ls=ER::LCA(x,y);ll Len=W[x]+W[y]-2*W[Ls];
if(x^Ls) T[x].PB((Ques){i,(Node){y,Len+W[x]-2*z}}),D[ER::Jump(x,Ls)].PB(i);
if(y^Ls) T[y].PB((Ques){i,(Node){x,Len+W[y]-2*z}}),D[ER::Jump(y,Ls)].PB(i);
}Ans=-5e18;GA(1,0);if(Ans>-1e18)printf("%lld\n",Ans/2);else puts("F");
}
int main(){
freopen("1.in","r",stdin);freopen("1.out","w",stdout);
int t;scanf("%d",&t);while(t--) Solve();
}
标签:P4775,int,luogu,Mx,&&,Line,NOI2018,id,ER
From: https://www.cnblogs.com/275307894a/p/17003076.html