Luogu3345 [ZJOI2015]幻想乡战略游戏
题面:良心洛谷
解析
动态点分治。假定我们已经确定了补给点,可以通过在点分树上(O(logn))统计答案,修改亦可(O(logn))做到,具体的话就是维护一下当前重心(w)的(sum_{v} d_v)与(sum_{v} d_vdist(v,w)),在多维护一个父节点信息,容斥即可。现在考虑如何确定补给点?还是在点分树上操作(因为这样能保证复杂度为(O(logn)),我们视度数为常数),每一次选最优的子树向下走即可,若走不动,那么当前点就是答案了。
代码
// luogu-judger-enable-o2
#include<cmath>
#include<cstdio>
#include<iostream>
#define N 100005
#define LL long long
using namespace std;
const int nlog=17;
inline int In(){
char c=getchar(); int x=0,ft=1;
for(;c<'0'||c>'9';c=getchar()) if(c=='-') ft=-1;
for(;c>='0'&&c<='9';c=getchar()) x=x*10+c-'0';
return x*ft;
}
inline int max(int a,int b){
return a>b?a:b;
}
int n,m,h[N],e_tot=0;
struct Edge{ int to,nex,d; }e[N<<1];
inline void add(int u,int v,int w){
e[++e_tot]=(Edge){v,h[u],w}; h[u]=e_tot;
}
int d[N],p[N<<1][nlog+5],dfn[N],dfs_clock=0;
void dfs(int u,int pre,int dep){
d[u]=dep; p[++dfs_clock][0]=u; dfn[u]=dfs_clock;
for(int i=h[u],v;i;i=e[i].nex){
v=e[i].to; if(v==pre) continue;
dfs(v,u,dep+e[i].d); p[++dfs_clock][0]=u;
}
}
int _p[nlog+5];
inline void get_st(){
_p[0]=1; for(int i=1;i<=nlog;++i) _p[i]=_p[i-1]*2;
for(int j=1;j<=nlog;++j)
for(int i=1;i+_p[j]<=dfs_clock;++i)
p[i][j]=d[p[i][j-1]]<d[p[i+_p[j-1]][j-1]]
?p[i][j-1]:p[i+_p[j-1]][j-1];
}
inline int LCA(int x,int y){
if(dfn[x]>dfn[y]) swap(x,y);
int k=log(dfn[y]-dfn[x]+1)/log(2);
return d[p[dfn[x]][k]]<d[p[dfn[y]-_p[k]+1][k]]?
p[dfn[x]][k]:p[dfn[y]-_p[k]+1][k];
}
inline int dist(int x,int y){
return d[x]+d[y]-2*d[LCA(x,y)];
}
int Sz,Sp_root,root,sz[N],f[N]; bool vis[N];
void get_rt(int u,int pre){
sz[u]=1; f[u]=0;
for(int i=h[u],v;i;i=e[i].nex){
v=e[i].to; if(vis[v]||v==pre) continue;
get_rt(v,u); sz[u]+=sz[v]; f[u]=max(f[u],sz[v]);
}
f[u]=max(f[u],Sz-sz[u]); if(f[u]<f[root]) root=u;
}
int fa[N],_g[N][nlog+5];
void Solve(int u,int pre,int dep){
vis[u]=1; fa[u]=pre; int Oth_sz=Sz-sz[u];
for(int i=h[u],v;i;i=e[i].nex){
v=e[i].to; if(vis[v]) continue;
Sz=sz[v]>sz[u]?Oth_sz:sz[v]; root=0;
get_rt(v,u); _g[v][dep]=root;
Solve(root,u,dep+1);
}
}
int sz_o[N]; LL sum_o[N],sum_f[N];
inline void Modify(int u,int C){
sz_o[u]+=C;
for(int p=fa[u],l_p=u,dis;p!=-1;p=fa[l_p=p]){
dis=dist(u,p); sz_o[p]+=C;
sum_o[p]+=1ll*C*dis; sum_f[l_p]+=1ll*C*dis;
}
}
inline LL Query(int u){
LL ans=0; ans+=sum_o[u];
for(int p=fa[u],l_p=u,dis,y;p!=-1;p=fa[l_p=p]){
dis=dist(u,p); ans+=1ll*dis*(sz_o[p]-sz_o[l_p]);
ans+=sum_o[p]; ans-=sum_f[l_p];
}
return ans;
}
inline LL get_ans(){
LL m_ans,S; int u=Sp_root,y;
for(int d=0;;++d){
m_ans=Query(u); y=u;
for(int i=h[u],v;i;i=e[i].nex){
v=e[i].to; if(!_g[v][d]) continue;
if(S=Query(v)<m_ans) m_ans=S,y=_g[v][d];
}
if(y==u) break; u=y;
}
return m_ans;
}
int main(){
n=In(); m=In();
for(int i=1,u,v,w;i<n;++i){
u=In(); v=In(); w=In();
add(u,v,w); add(v,u,w);
}
dfs(1,0,0); get_st();
Sz=f[0]=n; root=0; get_rt(1,-1);
Sp_root=root; Solve(root,-1,0);
for(int i=1,u,val;i<=m;++i){
u=In(); val=In(); Modify(u,val);
printf("%lld
",get_ans());
}
return 0;
}