luogu P3345 [ZJOI2015]幻想乡战略游戏
本来当成点分树练手题,然后写成动态重心QoT 17了(
首先根据我们分析重心那套\(\frac{n}{2}\)理论我们发现这个东西和边权半毛钱关系没有。
具体的,这道题要求的就是带权重心,而根据普通树重心那套理论,只要一个点的任意子树大小都 \(\leq \frac{n}{2}\)那么这个点就是重心中的一个。
根据QoT的那套理论,一个点的任意子树大小不超过\(\frac{n}{2}\)意味着它的子树大小至少为\(\frac{n}{2}\),则点权dfs序列中最中间的一个点一定在这个重心的子树内,因此可以用树状数组上倍增找到这个中间点,然后再往上倍增找到第一个子树大小大于等于\(\frac{n}{2}\)且最深的点就是重心了。
得到重心以后可以套路的拆掉距离的式子,然后得到两个平凡的东西和一个关于LCA深度的东西,关于LCA深度的东西可以用LNOI2014那题的方法每个被修改点暴力往上差分修改即可。时间复杂度\(O(n\log ^2n)\),常数非常小。
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) ((k+1)*(x)+(y))
#define R(n) (rnd()%(n)+1)
#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=100000+5,M=N<<2|5,K=(1<<16)+5,mod=998244353,M1=998244353,M2=1e9+7,Mod=mod-1;const db eps=1e-5;
int n,m,k,x,y,z,Id[N],Ih,Df[N],En[N],Si[N],Sn[N],fa[N],Tp[N],W[N],A[N],f[N][20],lg[N],d[N];ll Ts,Fs;struct Edge{int to,w;};vector<Edge> S[N];
void dfs1(int x,int La){d[x]=d[fa[x]=f[x][0]=La]+1;for(int i=1;f[x][i-1];i++) f[x][i]=f[f[x][i-1]][i-1];Si[x]=1;for(Edge i:S[x]) i.to^La&&(W[i.to]=W[x]+i.w,dfs1(i.to,x),Si[x]+=Si[i.to],Si[Sn[x]]<Si[i.to]&&(Sn[x]=i.to));}
void dfs2(int x,int La){Tp[x]=La;Df[Id[x]=En[x]=++Ih]=x;if(!Sn[x]) return;dfs2(Sn[x],La);for(Edge i:S[x]) i.to^fa[x]&&i.to^Sn[x]&&(dfs2(i.to,i.to),0);En[x]=Ih;}
namespace TA{
int f[N];void Ins(int x,int y){Fs+=1ll*y*W[Df[x]];Ts+=y;while(x<=n) f[x]+=y,x+=x&-x;}
int Qry(int x){int Ans=0;while(x) Ans+=f[x],x-=x&-x;return Ans;}
int Find(){int x=0,Ps=0;for(int i=lg[n];~i;i--) (Ps+f[x+(1<<i)])*2<=Ts&&x+(1<<i)<=n&&(x+=(1<<i),Ps+=f[x]);return Df[x+1];}
}
namespace Tree{
#define ls v<<1
#define rs v<<1|1
ll f[M],g[M],fl[M];void PF(int x,ll w){f[x]+=w*fl[x];g[x]+=w;}void P(int v){g[v]&&(PF(ls,g[v]),PF(rs,g[v]),g[v]=0);}void Up(int v){f[v]=f[ls]+f[rs];}
void BD(int l=1,int r=n,int v=1){if(l==r) {fl[v]=W[Df[l]]-W[fa[Df[l]]];return;}int m=l+r>>1;BD(l,m,ls);BD(m+1,r,rs);fl[v]=fl[ls]+fl[rs];}
void Ins(int x,int y,int z,int l=1,int r=n,int v=1){if(x<=l&&r<=y) return PF(v,z);int m=l+r>>1;P(v);x<=m&&(Ins(x,y,z,l,m,ls),0);y>m&&(Ins(x,y,z,m+1,r,rs),0);Up(v);}
ll Qry(int x,int y,int l=1,int r=n,int v=1){if(x<=l&&r<=y) return f[v];int m=l+r>>1;P(v);return (x<=m?Qry(x,y,l,m,ls):0)+(y>m?Qry(x,y,m+1,r,rs):0);}
#undef ls
#undef rs
}
void Ins(int x,int y){TA::Ins(Id[x],y);while(x) Tree::Ins(Id[Tp[x]],Id[x],y),x=fa[Tp[x]];}
void Qry(){int i,x=TA::Find();ll Ans=0;for(i=lg[d[x]];~i;i--) f[x][i]&&(TA::Qry(En[f[x][i]])-TA::Qry(Id[f[x][i]]-1))*2<Ts&&(x=f[x][i]);(TA::Qry(En[x])-TA::Qry(Id[x]-1))*2<Ts&&(x=f[x][0]);/*cerr<<x<<'\n';*/Ans=Fs+W[x]*Ts;while(x) Ans-=2*Tree::Qry(Id[Tp[x]],Id[x]),x=fa[Tp[x]];printf("%lld\n",Ans);}
int main(){
freopen("1.in","r",stdin);
int i,j;scanf("%d%d",&n,&m);for(i=1;i<n;i++) scanf("%d%d%d",&x,&y,&z),S[x].PB((Edge){y,z}),S[y].PB((Edge){x,z});dfs1(1,0);dfs2(1,1);for(i=2;i<=n;i++) lg[i]=lg[i/2]+1;
Tree::BD();while(m--)scanf("%d%d",&x,&y),Ins(x,y),Qry();
}