2018.08.28 洛谷P3345 [ZJOI2015]幻想乡战略游戏(点分树)

版权声明:随意转载哦......但还是请注明出处吧: https://blog.csdn.net/dreaming__ldx/article/details/82146280

传送门
题目就是要求维护带权重心。
因此破题的关键点自然就是带权重心的性质。
这时发现直接找带权重心是O(n)的,考虑优化方案。
发现点分树的树高是logn级别的,并且对于以u为根的树,带权重心要么就是u,要么存在于u的某一个儿子为根的子树中。
由于带权重心只有一个,因此只需要从根节点开始向下跳,跳不动了就是答案。
代码:

#include<bits/stdc++.h>
#define N 100005
#define ll long long
using namespace std;
inline int read(){
int ans=0,w=1;
char ch=getchar();
while(!isdigit(ch)){if(ch=='-')w=-1;ch=getchar();}
while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch^48),ch=getchar();
return ans*w;
}
int n,m,siz[N],first[N],lastrt,cnt,tot,sum,rt,vis[N],pa[N],Log[N<<2],fsiz[N];
ll d1[N],d2[N],sumv[N];
struct edge{int v,next,w;}e[N<<1];
inline void Add(int u,int v,int w){e[++cnt].v=v,e[cnt].next=first[u],e[cnt].w=w,first[u]=cnt;}
struct Tree{
int first[N],cnt,tot,st[N<<2][21],d[N],dfn[N];
edge t[N<<1];
inline int min(int a,int b){return a<b?a:b;}
inline void add(int u,int v,int w){t[++cnt].v=v,t[cnt].w=w,t[cnt].next=first[u],first[u]=cnt;}
inline int getdis(int u,int v){
    if(dfn[u]>dfn[v])swap(u,v);
    int tmp=Log[dfn[v]-dfn[u]+1];
    return d[u]+d[v]-2*min(st[dfn[u]][tmp],st[dfn[v]-(1<<tmp)+1][tmp]);
}
inline void dfs(int p,int fa){
    st[(dfn[p]=++tot)][0]=d[p];
    for(int i=first[p];i;i=t[i].next){
        int v=t[i].v;
        if(v==fa)continue;
        d[v]=d[p]+t[i].w;
        dfs(v,p);
        st[++tot][0]=d[p];
    }
}
inline void init(){
    dfs(1,0);
    for(int i=1;(1<<i)<=tot;++i)
        for(int j=1;(1<<i)+j-1<=tot&&j<=tot;++j)
            st[j][i]=min(st[j][i-1],st[j+(1<<(i-1))][i-1]);
}
}T;
inline int max(int a,int b){return a>b?a:b;}
inline void getrt(int p,int fa){
siz[p]=1,fsiz[p]=0;
for(int i=T.first[p];i;i=T.t[i].next){
    int v=T.t[i].v;
    if(vis[v]||v==fa)continue;
    getrt(v,p),siz[p]+=siz[v],fsiz[p]=max(fsiz[p],siz[v]);
}
fsiz[p]=max(fsiz[p],sum-siz[p]);
if(fsiz[p]<fsiz[rt])rt=p;
}
inline void solve(int p,int fa){
vis[p]=1,pa[p]=fa;
for(int i=T.first[p];i;i=T.t[i].next){
    int v=T.t[i].v;
    if(vis[v])continue;
    fsiz[(rt=0)]=sum=siz[v],getrt(v,0),Add(p,rt,v);
    solve(rt,p);
}
}
inline void update(int p,int val){
sumv[p]+=val;
for(int i=p;pa[i];i=pa[i]){
    int dis=T.getdis(pa[i],p);
    d1[pa[i]]+=(ll)dis*val,d2[i]+=(ll)dis*val,sumv[pa[i]]+=val;
}
}
inline ll calc(int p){
ll res=d1[p];
for(int i=p;pa[i];i=pa[i]){
    int dis=T.getdis(pa[i],p);
    res+=d1[pa[i]]-d2[i]+dis*(sumv[pa[i]]-sumv[i]);
}
return res;
}
inline ll query(int p){
ll ans=calc(p);
for(int i=first[p];i;i=e[i].next){
    ll tmp=calc(e[i].w);
    if(tmp<ans)return query(e[i].v);
}
return ans;
}
int main(){
Log[0]=-1,n=read(),m=read();
for(int i=1;i<n;++i){
    int x=read(),y=read(),z=read();
    T.add(x,y,z),T.add(y,x,z);
}
for(int i=1;i<(N<<2);++i)Log[i]=Log[i>>1]+1;
T.init(),sum=n,fsiz[(rt=0)]=n,getrt(1,0),lastrt=rt,solve(rt,0),rt=lastrt;
while(m--){
    int x=read(),y=read();
    update(x,y),cout<<query(rt)<<'\n';
}
return 0;
}

猜你喜欢

转载自blog.csdn.net/dreaming__ldx/article/details/82146280