【题目】
原题地址
给定一棵带边权树和树上的 m m m条链,每条链有一个花费 c i c_i ci,两条有边交的链的价值定义为:链并的边权和-两条链的花费。求最大价值。
(需要用一个 l o g log log的做法)
【题目分析】
这题是 S C SC SC在看,我跑过去凑热闹,然后我们搞了一个星期 … \dots …两个部分都搞出了一个可行的做法,然后看题解 … \dots …震惊,还能这样做。
(update:如果有大佬能把第二个常数巨大的代码卡过,感激不尽!)
【解题思路】
题目给出了 S 1 ( l c a 不 同 ) S1(lca不同) S1(lca不同)和 S 2 ( l c a 相 同 ) S2(lca相同) S2(lca相同)两个部分,我们可以朝这两个方向思考。
考虑 S 1 S1 S1,观察到对于 l c a lca lca不同的两条链,两条链的交必然是直上直下的一段,即链交深度是连续的,因此我们可以把一条链拆成两条直上直下的链考虑。
现在对于两条链 ( u 1 , v 1 , l c a 1 ) 和 ( u 2 , v 2 , l c a 2 ) (u_1,v_1,lca_1)和(u_2,v_2,lca_2) (u1,v1,lca1)和(u2,v2,lca2),考虑枚举链交深度较深的交点 x x x,那么显然这两条链的下端点一定在 x x x的不同儿子子树中。
我们要求的答案 a n s = l e n 1 + l e n 2 − c o s t 1 − c o s t 2 − d e p x + m a x d e p ( l c a 1 , l c a 2 ) ans=len_1+len_2-cost_1-cost_2-dep_x+maxdep(lca_1,lca_2) ans=len1+len2−cost1−cost2−depx+maxdep(lca1,lca2)(这里深度为带权深度。)
这里一开始的想法是枚举一个点作为链交的一个交点,可以通过分析得到一个通过线段树合并以及多次查询的 O ( m l o g 2 n ) O(mlog^2n) O(mlog2n)的做法,但是略为复杂在次不作阐述。
我们对每个点记 f i , j f_{i,j} fi,j表示下端点在 i i i子树内,上端不带权深度为 j j j的最大 l e n − c o s t len-cost len−cost,可以用启发式合并或线段树合并解决这个 d p dp dp。
具体来说,我们需要按不带权深度从小到大为序建出线段树。
然后在 u 1 u_1 u1的线段树上插入 l c a 1 lca_1 lca1,在 u 2 u_2 u2的线段树上插入 l c a 2 lca_2 lca2,合并两棵线段树时,深度小的节点要在深度大的区间中统计贡献,即对于两棵树 x , y x,y x,y,要用( x x x的 l s o n lson lson和 y y y的 r s o n rson rson)以及( y y y的 l s o n lson lson和 x x x的 r s o n rson rson)分别贡献答案。
那么这一部分的时间复杂度是 O ( m l o g n ) O(mlogn) O(mlogn)的。
现在考虑 S 2 S2 S2,这里两条链的交可能不是直上直下的,因此比较难处理。
一个比较明显的方向是枚举两条链的公共 l c a lca lca。
我们对整颗树进行轻重链剖分,对于每个节点,记录子树中除重儿子外,所有轻儿子的最大 l e n − c o s t len-cost len−cost,那么对于每个节点如果要算出答案,就需要在重儿子的部分进行dfs,我们用线段树合并处理这个问题,这样处理起来是 O ( n l o g 2 n ) O(nlog^2n) O(nlog2n)的。
S C SC SC给出一种思路是处理出整颗树的欧拉序,对于每个节点已经知道了它在欧拉序中出现的位置,这样的话知道每条链端点的欧拉序。
观察到选择两条链,实际上就是在一个节点选择它两棵子树中的不同的链端点,再找到对应的端点进行运算,我们同样可以考虑用线段树合并进行优化。
具体实现我们可以对于每个点维护最大的 ( 到 链 l c a 距 离 − c o s t ) (到链lca距离-cost) (到链lca距离−cost),然后类似 S 1 S1 S1的做法左右进行贡献。由于我太蒻,这部分我没有特别听清楚,不过大概YY了一下应该是可行的。复杂度是 O ( m l o g n ) O(mlogn) O(mlogn)的。
(update:这个做法在LOJ上得到了95分,第6个点被卡TLE了,欧拉序有一些细节问题需要处理,比方说合并上在根节点要特判之类的。)
第三种思路,观察到一个性质:链并的两倍=两条链长+ d i s ( u 1 , u 2 ) + d i s ( v 1 , v 2 ) dis(u_1,u_2)+dis(v_1,v_2) dis(u1,u2)+dis(v1,v2)
那么我们枚举 u 1 , u 2 u_1,u_2 u1,u2的 l c a lca lca,然后用树剖+线段树强行维护,然后选出来自不同儿子子树的两个 u u u,使得它们对应 v v v的距离- c o s t cost cost+ u 的 深 度 u的深度 u的深度- 2 ∗ l c a u 2*lca_u 2∗lcau最大,而 l c a u lca_u lcau是个常数,那么我们通过附加点连边权为 链 长 − c o s t 链长-cost 链长−cost的边,就可以转化为最远点对问题,这个问题我们可以通过 d f s dfs dfs直接合并。
这里实现的时候我们需要建出虚树然后自下而上合并,也可以直接启发式合并。复杂度是 O ( m l o g n ) O(mlogn) O(mlogn)的。
据说的还有一种点分治的做法,考虑所有过重心的链,转化为过一个点的情况,时间复杂度是一样的,但是还要加一个 O ( n l o g n ) O(nlogn) O(nlogn)的点分,问题不大。
总之这道题十分复杂,写起来也可能会很乱,需要十分强大的分析能力及代码能力。
写完以后再次感受到了 n a m e s p a c e namespace namespace的好处。
【参考代码】
我的:
#include
#define pb push_back
#define mkp make_pair
#define fi first
#define se second
using namespace std;
typedef long long LL;
typedef pair<LL,LL> pll;
const LL INF=(LL)1000000000000000000;
const int N=5e4+10;
int n,m,ind,tot;
int top[N],fa[N],dep[N],siz[N],head[N],son[N],dfn[N];
LL ans,len[N],c[N<<2];
vector<int>st[N];
map<int,LL>mp[N];
LL read()
{
LL ret=0;char c=getchar();
while(!isdigit(c)) c=getchar();
while(isdigit(c)) ret=ret*10+(c^48),c=getchar();
return ret;
}
struct data{int x,y,z;LL c,len;}dat[N<<1];
struct Tway{int v,w,nex;}e[N<<1];
void add(int u,int v,int w){e[++tot]=(Tway){v,w,head[u]};head[u]=tot;}
void dfs1(int x,int dp,LL l)
{
dep[x]=dp;len[x]=l;siz[x]=1;
for(int i=head[x];i;i=e[i].nex)
{
int v=e[i].v;
dfs1(v,dp+1,l+e[i].w);
siz[x]+=siz[v];
if(siz[son[x]]<siz[v]) son[x]=v;
}
}
void dfs2(int x,int tp)
{
top[x]=tp;dfn[x]=++ind;
if(son[x]) dfs2(son[x],tp);
for(int i=head[x];i;i=e[i].nex)
{
int v=e[i].v;
if(v==son[x]) continue;
dfs2(v,v);
}
}
int lca(int x,int y)
{
while(top[x]^top[y])
{
if(dep[top[x]]<dep[top[y]]) swap(x,y);
x=fa[top[x]];
}
return dep[x]<dep[y]?x:y;
}
void totinit()
{
n=read();
ans=-INF;tot=ind=0;
for(int i=1;i<=n;++i)
head[i]=son[i]=0,st[i].clear(),mp[i].clear();
for(int i=1;i<n;++i)
{
int u=read(),v=read(),w=read();
fa[v]=u;add(u,v,w);
}
dfs1(1,1,0);dfs2(1,1);
//for(int i=1;i<=n;++i) printf("%d %d %d\n",siz[i],fa[i],son[i]); puts("");
m=read();
for(int i=1;i<=m;++i)
{
dat[i].x=read();dat[i].y=read();dat[i].c=read();
dat[i].z=lca(dat[i].x,dat[i].y);
dat[i].len=len[dat[i].x]+len[dat[i].y]-2*len[dat[i].z];
//printf("%d %d %d %lld\n",dat[i].x,dat[i].y,dat[i].z,dat[i].len);
if(dat[i].x==dat[i].y) continue;
if(dat[i].x>dat[i].y) swap(dat[i].x,dat[i].y);
if(mp[dat[i].x].count(dat[i].y))
{
ans=max(ans,dat[i].len-mp[dat[i].x][dat[i].y]-dat[i].c);
mp[dat[i].x][dat[i].y]=min(mp[dat[i].x][dat[i].y],dat[i].c);
}
else mp[dat[i].x][dat[i].y]=dat[i].c;
st[dat[i].z].pb(i);
c[i]=dat[i].len-2*dat[i].c+len[dat[i].y];
c[i+m]=dat[i].len-2*dat[i].c+len[dat[i].x];
}
//for(int i=1;i<=2*m;++i) printf("%lld ",c[i]); puts("");
}
namespace S1
{
pll t[N*40],nw;
int sz,ls[N*40],rs[N*40],rt[N];
LL ddd;
void init()
{
sz=0;
for(int i=1;i<=n;++i) rt[i]=0;
}
void newnode(int &x){x=++sz;t[x]=mkp(-INF,-INF);ls[x]=rs[x]=0;}
pll cmp(pll x,pll y){return mkp(max(x.fi,y.fi),max(x.se,y.se));}
void insert(int &x,int l,int r,int p)
{
//printf("%d %d %d\n",x,l,r);
if(!x) newnode(x);
if(l==r){t[x]=cmp(t[x],nw);return;}
int mid=(l+r)>>1;
if(p<=mid) insert(ls[x],l,mid,p);
else insert(rs[x],mid+1,r,p);
t[x]=cmp(t[ls[x]],t[rs[x]]);
//printf("%lld %lld\n",t[x].fi,t[x].se);
}
void update(int x,int l,int r,int p)
{
if(!x) return;
if(l==r){t[x]=nw;return;}
int mid=(l+r)>>1;
if(p<=mid) update(ls[x],l,mid,p);
else update(rs[x],mid+1,r,p);
t[x]=cmp(t[ls[x]],t[rs[x]]);
//printf("%lld %lld\n",t[x].fi,t[x].se);
}
void merge(int &x,int y,int l,int r,LL a,LL b)
{
ans=max(ans,max(t[x].se+a,t[x].fi+b)-ddd);
if(!y) return;
if(!x){x=y;return;}
if(l==r){t[x]=cmp(t[x],t[y]);return;}
int mid=(l+r)>>1;
merge(ls[x],ls[y],l,mid,a,max(b,t[rs[y]].se));
merge(rs[x],rs[y],mid+1,r,max(a,t[ls[y]].fi),b);
t[x]=cmp(t[ls[x]],t[rs[x]]);
}
void calc(int x,int l,int r,LL a,LL b)
{
ans=max(ans,max(t[x].fi+a,+t[x].se+a)-ddd);
if(!x || l==r) return;
int mid=(l+r)>>1;
calc(ls[x],l,mid,a,max(b,t[rs[x]].se));
calc(rs[x],mid+1,r,max(a,t[ls[x]].fi),b);
}
void updata(int p)
{
nw=mkp(-INF,-INF);
update(rt[p],1,n,dep[p]);ddd=len[p];
calc(rt[p],1,n,-INF,-INF);
for(int i=head[p];i;i=e[i].nex)
{
int v=e[i].v;
updata(v);nw=mkp(-INF,-INF);
update(rt[v],1,n,dep[p]);ddd=len[p];
merge(rt[p],rt[v],1,n,-INF,-INF);
}
}
void solve()
{
init();t[0]=mkp(-INF,-INF);
for(int i=1;i<=m;++i)
{
if(dat[i].x==dat[i].y) continue;
nw=mkp(dat[i].len-dat[i].c,dat[i].len-dat[i].c+len[dat[i].z]);
//printf("%lld %lld\n",nw.fi,nw.se);
insert(rt[dat[i].x],1,n,dep[dat[i].z]);
insert(rt[dat[i].y],1,n,dep[dat[i].z]);
}
updata(1);
}
};
namespace S2
{
int A[N],B[N],pl[N<<2],stk[N];
LL ddd,L[N];
vector<int>vt[N];
bool cmp(int x,int y){return dfn[x]<dfn[y];}
void addedge(int x,int y){vt[x].pb(y);}
void build(int x)
{
pl[0]=0;
for(int i=0;i<(int)st[x].size();++i)
pl[++pl[0]]=dat[st[x][i]].x,pl[++pl[0]]=dat[st[x][i]].y;
sort(pl+1,pl+pl[0]+1,cmp);
//printf("%d\n",pl[0]);
int tp=1;stk[tp]=x;
for(int i=1;i<=pl[0];++i)
{
int t=lca(stk[tp],pl[i]),now=pl[i];
while(dep[stk[tp]]>dep[t])
{
if(dep[stk[tp-1]]<=dep[t])
{
addedge(t,stk[tp--]);
if(stk[tp]^t) stk[++tp]=t;
break;
}
addedge(stk[tp-1],stk[tp]);--tp;
}
if(stk[tp]^now) stk[++tp]=now;
}
while(--tp) addedge(stk[tp],stk[tp+1]);
}
LL getdis(int x,int y)
{
int cx=x>m?dat[x-m].y:dat[x].x,cy=y>m?dat[y-m].y:dat[y].x;
return len[cx]+len[cy]-2*len[lca(cx,cy)]+c[x]+c[y];
}
void insp(int p,int x,int y)
{
//printf("%d %d %d\n",p,x,y);
if(!A[x]) A[x]=y;
else if(!B[x])
{
B[x]=y;L[x]=getdis(A[x],B[x]);
if(x^p) ans=max(ans,L[x]/2-len[x]);
}
else
{
int a=A[x],b=B[x];LL l=L[x],las;
if((las=getdis(A[x],y))>l) l=las,a=A[x],b=y;
if((las=getdis(B[x],y))>l) l=las,a=y,b=B[x];
A[x]=a;B[x]=b;L[x]=l;
if(x^p) ans=max(ans,L[x]/2-len[x]);
}
//printf("%d %d %lld\n",A[x],B[x],L[x]);
}
void init(int x){A[x]=B[x]=0;L[x]=-INF;vt[x].clear();}
void merge(int x,int y,LL nw)
{
//printf("%d %d %lld\n",x,y,nw);
int a=A[x],b=B[x];
if(!a && !b) {A[x]=A[y];B[x]=B[y];L[x]=L[y]; return;}
LL l=L[x],las;
for(int i=0;i<=1;++i) for(int j=0;j<=1;++j)
{
int X=i?A[x]:B[x];
int Y=j?A[y]:B[y];
if(!X || !Y) continue;
ans=max(ans,getdis(X,Y)/2-nw);
if((las=getdis(X,Y))>l) l=las,a=X,b=Y;
}
if(L[y]>l) a=A[y],b=B[y],l=L[y];
A[x]=a,B[x]=b,L[x]=l;
//printf("%d %d %d\n",A[x],B[x],L[x]);
}
void dfs(int x,int r)
{
//printf("%d\n",vt[x].size());
for(int i=0;i<(int)vt[x].size();++i)
{
int v=vt[x][i];dfs(v,r);
//printf("%d %d %d\n",x,v,r);
if(x^r) merge(x,v,len[x]);
init(v);
}
}
void query(int x)
{
for(int i=0;i<(int)st[x].size();++i)
{
if(dat[st[x][i]].x==dat[st[x][i]].y) continue;
insp(x,dat[st[x][i]].x,st[x][i]+m);
insp(x,dat[st[x][i]].y,st[x][i]);
}
dfs(x,x);init(x);
}
void solve()
{
for(int i=1;i<=n;++i) L[i]=-INF;
for(int i=1;i<=n;++i)
if(st[i].size()>1) build(i),query(i);
}
};
void solve()
{
totinit();
S1::solve();
S2::solve();
if(ans<=-1000000000000000) puts("F");
else printf("%lld\n",ans);
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("LOJ2722.in","r",stdin);
freopen("LOJ2722.out","w",stdout);
#endif
int T=read();
while(T--) solve();
return 0;
}
S C SC SC的:
#include
#define mid (tl+tr)>>1
#define pbk push_back
#define clz __builtin_clz
using namespace std;
typedef long long ll;
const int maxn = 5e4 + 10;
const ll INFLL = 0x3f3f3f3f3f3f3f3fll;
inline char Getchar()
{
static char c[100000],*p1=c,*p2=c;
return p1==p2&&(p2=(p1=c)+fread(c,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline ll read()
{
ll x=0;char c=Getchar();
for(;c<'0'||c>'9';c=Getchar());
for(;c>='0'&&c<='9';c=Getchar()) x=x*10+(c^48);
return x;
}
void write(ll x)
{
if(x<0) putchar('-'),x=-x;
if(x>9) write(x/10);
putchar(x%10^48);
}
inline ll Max(ll a,ll b){return a<b?b:a;}
int n,m,en,head[maxn];ll fans;
int fa[maxn][20],dep[maxn];ll dis[maxn];
vector<int> elr[maxn];int elrn;
struct RMQ{
ll mi[20][maxn*2];
ll &operator [](int p){return mi[0][p];}
void init()
{
int i,j;
for(i=1;(1<<i)<=2*n;i++)
{
for(j=0;j+(1<<i)<=2*n;j++) mi[i][j]=min(mi[i-1][j],mi[i-1][j+(1<<(i-1))]);
}
}
inline ll ask(int l,int r)//notice! array = [l,r)
{
int d=31-clz(r-l);
//printf("RMQ ask %d %d ans=%lld\n",l,r,-min(mi[d][l],mi[d][r-(1<
return -min(mi[d][l],mi[d][r-(1<<d)]);
}
}R;
struct edge{
int v,l,n;
}e[maxn<<1];
namespace Sub
{
ll x,dmx,did,ndis;
bool renew;
struct node{
int lc,rc;
ll mx,mxmi,mimx;
ll smx,smxmi,smimx;
int mxid,mxmiid,mimxid;
inline void renew(ll wdis,int id,int tl,int tr)
{
if(dmx>mx)
{
if(id!=mxid) smx=mx,smxmi=mxmi,smimx=mimx;
mx=dmx;mxmi=mimx=R.ask(tl,tr)+dmx;
mxid=mxmiid=mimxid=id;
}
else if(dmx>smx)
{
smx=dmx;smxmi=smimx=R.ask(tl,tr)+dmx;
}
fans=max(fans,mx+smx+R.ask(tl,tr)-ndis+(wdis<<1));
}
inline ll operator + (const node &s)
{
ll ans=-INFLL;
if(mxid==s.mimxid) ans=Max(ans,Max(mx+s.smimx,smx+s.mimx));
else ans=Max(ans,mx+s.mimx);
if(mxmiid==s.mxid) ans=Max(ans,Max(mxmi+s.smx,smxmi+s.mx));
else ans=Max(ans,mxmi+s.mx);
return ans;
}
void init(){mx=mxmi=mimx=smx=smxmi=smimx=-INFLL;mxid=mxmiid=mimxid=lc=rc=0;}
}nt[maxn*80];int ntn;
struct tree{
int rt;ll wdis;
inline void up(int p,int tl,int tr)
{
int lc=nt[p].lc,rc=nt[p].rc;ll tmp;
if(nt[lc].mx>nt[rc].mx)
{
nt[p].mx=nt[lc].mx;nt[p].mxid=nt[lc].mxid;
nt[p].smx=Max(nt[lc].smx,(nt[rc].mxid==nt[p].mxid?nt[rc].smx:nt[rc].mx));
}
else
{
nt[p].mx=nt[rc].mx;nt[p].mxid=nt[rc].mxid;
nt[p].smx=Max(nt[rc].smx,(nt[lc].mxid==nt[p].mxid?nt[lc].smx:nt[lc].mx));
}
if(Max(nt[lc].mxmi,nt[rc].mxmi)<(tmp=Max(-INFLL,nt[lc].mx+R.ask(mid,tr))))
{
nt[p].mxmi=tmp;nt[p].mxmiid=nt[lc].mxid;
nt[p].smxmi=Max(Max((nt[lc].mxmiid==nt[p].mxmiid?nt[lc].smxmi:nt[lc].mxmi)
,(nt[rc].mxmiid==nt[p].mxmiid?nt[rc].smxmi:nt[rc].mxmi))
,Max(-INFLL,nt[lc].smx+R.ask(mid,tr)));
}
else if(nt[lc].mxmi>nt[rc].mxmi)
{
nt[p].mxmi=nt[lc].mxmi;nt[p].mxmiid=nt[lc].mxmiid;
nt[p].smxmi=Max(Max(nt[lc].smxmi
,(nt[rc].mxmiid==nt[p].mxmiid?nt[rc].smxmi:nt[rc].mxmi))
,(nt[lc].mxid==nt[p].mxmiid?Max(-INFLL,nt[lc].smx+R.ask(mid,tr)):tmp));
}
else
{
nt[p].mxmi=nt[rc].mxmi;nt[p].mxmiid=nt[rc].mxmiid;
nt[p].smxmi=Max(Max(nt[rc].smxmi
,(nt[lc].mxmiid==nt[p].mxmiid?nt[lc].smxmi:nt[lc].mxmi))
,(nt[lc].mxid==nt[p].mxmiid?Max(-INFLL,nt[lc].smx+R.ask(mid,tr)):tmp));
}
if(Max(nt[lc].mimx,nt[rc].mimx)<(tmp=Max(-INFLL,R.ask(tl,mid)+nt[rc].mx)))
{
nt[p].mimx=tmp;nt[p].mimxid=nt[lc].mxid;
nt[p].smimx=Max(Max((nt[lc].mimxid==nt[p].mimxid?nt[lc].smimx:nt[lc].mimx)
,(nt[rc].mimxid==nt[p].mimxid?nt[rc].smimx:nt[rc].mimx))
,Max(-INFLL,R.ask(tl,mid)+nt[rc].smx));
}
else if(nt[lc].mimx>nt[rc].mimx)
{
nt[p].mimx=nt[lc].mimx;nt[p].mimxid=nt[lc].mimxid;
nt[p].smimx=Max(Max(nt[lc].smimx
,(nt[rc].mimxid==nt[p].mimxid?nt[rc].smimx:nt[rc].mimx))
,(nt[rc].mxid==nt[p].mimxid?Max(-INFLL,R.ask(tl,mid)+nt[rc].smx):tmp));
}
else
{
nt[p].mimx=nt[rc].mimx;nt[p].mimxid=nt[rc].mimxid;
nt[p].smimx=Max(Max(nt[rc].smimx
,(nt[lc].mimxid==nt[p].mimxid?nt[lc].smimx:nt[lc].mimx))
,(nt[rc].mxid==nt[p].mimxid?Max(-INFLL,R.ask(tl,mid)+nt[rc].smx):tmp));
}
if(renew) fans=Max(fans,nt[lc]+nt[rc]-ndis+(wdis<<1));
}
int tedit(int p,int tl,int tr)
{
if(!p) p=ntn++,nt[p].init();
if(tl==tr-1)
{
nt[p].renew(wdis,did,tl,tr);
return p;
}
if(x<mid) nt[p].lc=tedit(nt[p].lc,tl,mid);
else nt[p].rc=tedit(nt[p].rc,mid,tr);
renew=true;up(p,tl,tr);return p;
}
void edit(ll X,ll DMX,ll DID,ll NDIS)
{
x=X;dmx=DMX;did=DID;ndis=NDIS;
rt=tedit(rt,0,maxn<<1);
}
int merge(int x,int y,int tl,int tr)
{
if(!x) return y;if(!y) return x;
if(tl==tr-1)
{
nt[x].mx=Max(nt[x].mx,nt[y].mx);nt[x].mxmi=nt[x].mimx=R.ask(tl,tr)+nt[x].mx;
return x;
}
fans=Max(fans,nt[nt[x].lc]+nt[nt[y].rc]-ndis+(wdis<<1));
fans=Max(fans,nt[nt[y].lc]+nt[nt[x].rc]-ndis+(wdis<<1));
nt[x].lc=merge(nt[x].lc,nt[y].lc,tl,mid);
nt[x].rc=merge(nt[x].rc,nt[y].rc,mid,tr);
renew=false;up(x,tl,tr);
return x;
}
inline void mrg(tree &s,ll NDIS){ndis=NDIS;rt=merge(rt,s.rt,0,maxn<<1);}
};
}
namespace Main
{
struct node{
int lc,rc;
ll lmx,rmx;
Sub::tree T;
void init(){lmx=rmx=-INFLL;T.rt=0;lc=rc=0;}
}nt[maxn*40];int ntn;
ll x,dl,dr;bool renew;
ll L;
Sub::tree *Tmp;
struct tree{
int rt;ll ndis;
inline void up(int p)
{
int lc=nt[p].lc,rc=nt[p].rc;
nt[p].lmx=Max(nt[lc].lmx,nt[rc].lmx);
nt[p].rmx=Max(nt[lc].rmx,nt[rc].rmx);
if(renew) fans=Max(fans,nt[lc].lmx+nt[rc].rmx-ndis);
}
int tedit(int p,int tl,int tr)
{
if(!p) p=ntn++,nt[p].init();
if(tl==tr-1)
{
nt[p].lmx=Max(nt[p].lmx,dl);nt[p].rmx=Max(nt[p].rmx,dr);
Tmp=&nt[p].T;
return p;
}
if(x<mid) nt[p].lc=tedit(nt[p].lc,tl,mid);
else nt[p].rc=tedit(nt[p].rc,mid,tr);
renew=true;up(p);return p;
}
Sub::tree *edit(ll X,ll DL,ll DR)
{
x=X;dl=DL;dr=DR;
rt=tedit(rt,0,maxn);
return Tmp;
}
int del(int p,int tl,int tr)
{
if(!p || L<=tl) return 0;
if(L<mid) nt[p].lc=del(nt[p].lc,tl,mid);
nt[p].rc=del(nt[p].rc,mid,tr);
renew=false;up(p);return p;
}
int merge(int x,int y,int tl,int tr)
{
if(!x) return y;if(!y) return x;//cerr<<"RUN";
if(tl==tr-1)
{
nt[x].lmx=Max(nt[x].lmx,nt[y].lmx);
nt[x].rmx=Max(nt[x].rmx,nt[y].rmx);
nt[x].T.mrg(nt[y].T,ndis);
return x;
}
fans=Max(fans,nt[nt[x].lc].lmx+nt[nt[y].rc].rmx-ndis);
fans=Max(fans,nt[nt[y].lc].lmx+nt[nt[x].rc].rmx-ndis);
nt[x].lc=merge(nt[x].lc,nt[y].lc,tl,mid);
nt[x].rc=merge(nt[x].rc,nt[y].rc,mid,tr);
renew=false;up(x);return x;
}
void mrg(tree &s){rt=merge(rt,s.rt,0,maxn);}
};
}
Main::tree T[maxn];
inline void addedge(int l,int u,int v)
{
e[en].v=v;e[en].l=l;e[en].n=head[u];head[u]=en++;
e[en].v=u;e[en].l=l;e[en].n=head[v];head[v]=en++;
}
inline int lca(int u,int v)
{
int i;if(dep[u]<dep[v]) swap(u,v);
for(i=31-clz(dep[u]-dep[v]);~i;i--) if((dep[u]-dep[v])>>i&1) u=fa[u][i];
if(u==v) return u;
for(i=31-clz(dep[u]);~i;i--) if(fa[u][i]!=fa[v][i]) u=fa[u][i],v=fa[v][i];
return fa[u][0];
}
void input_tree()
{
int i;
n=read();
en=elrn=1;memset(head,0,sizeof(int)*(n+1));memset(fa,0,sizeof(int)*20*(n+1));
for(i=1;i<=n;i++) elr[i].clear();
for(i=1;i<n;i++) addedge(read(),read(),read());
}
void dfs(int x)
{
int i;
R[elrn]=dis[x];elr[x].pbk(elrn++);//printf("%d ",dis[x]);
for(i=1;fa[x][i-1];i++) fa[x][i]=fa[fa[x][i-1]][i-1];
for(i=head[x];i;i=e[i].n) if(e[i].v!=fa[x][0])
{
dep[e[i].v]=dep[x]+1;dis[e[i].v]=dis[x]+e[i].l;fa[e[i].v][0]=x;
dfs(e[i].v);
R[elrn]=dis[x];elr[x].pbk(elrn++);//printf("%d ",dis[x]);
}
}
void input_way()
{
int i;unsigned int j;
int u,v,w;ll val;
Sub::tree *Tmp;
m=read();
fans=-INFLL;Main::ntn=Sub::ntn=1;
for(i=0;i<=n;i++) T[i].rt=0,T[i].ndis=dis[i];
for(i=1;i<=m;i++)
{
w=lca(u=read(),v=read());val=dis[u]+dis[v]-2*dis[w]-read();
if(u!=w){
Tmp=T[u].edit(dep[w]+1,val,val+dis[w]);Tmp->wdis=dis[w];
for(j=0;j<elr[v].size();j++) Tmp->edit(elr[v][j],val,i,dis[u]);
}
if(v!=w){
Tmp=T[v].edit(dep[w]+1,val,val+dis[w]);Tmp->wdis=dis[w];
for(j=0;j<elr[u].size();j++) Tmp->edit(elr[u][j],val,i,dis[v]);
}
//cerr<
}
}
void solve(int x)
{
int i;
for(i=head[x];i;i=e[i].n) if(e[i].v!=fa[x][0])
{
solve(e[i].v);
Main::L=dep[x]+1;T[e[i].v].del(T[e[i].v].rt,0,maxn);
T[x].mrg(T[e[i].v]);
}//printf("At x=%d fans=%lld\n",x,fans);
}
int main()
{
freopen("center.in","r",stdin);
freopen("center.out","w",stdout);
Sub::nt[0].init();Main::nt[0].init();
int tt=read();
while(tt--)
{
input_tree();
dfs(1);
R.init();
input_way();
solve(1);
//write(tt);putchar(' ');
if(fans<=-1e17) puts("F");
else write(fans),putchar('\n');
}
//cerr<
return 0;
}
【总结】
膜拜出题组。
CSDN的博客真的是越改越菜了,这个代码片颜色怎么换啊,怎么复制还去掉了换行符啊。