1. 程式人生 > >【BZOJ3924】幻想鄉戰略遊戲(動態點分治)

【BZOJ3924】幻想鄉戰略遊戲(動態點分治)

truct 產生 。。 sum 遊戲 stream str pos struct

【BZOJ3924】幻想鄉戰略遊戲(動態點分治)

題面

權限題。。。(窮死我了)
洛谷

題解

考慮不修改
發現一個貪心的做法
假設當前放在當前位置
如果它有一個子樹的兵的總數大於總數的一半
那麽,放到那個子樹的根節點上一定最優

那麽,現在是動態修改
考慮動態點分治
在每個點上維護子樹的兵的總數
子樹到上一層父親節點
向上走產生的貢獻的總和
以及接收到子節點的貢獻的總和
那麽,就可以計算當前點產生的貢獻

於是,從分治樹根開始向下貪心即可

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath> #include<algorithm> #include<set> #include<map> #include<vector> #include<queue> using namespace std; #define MAX 120000 #define ll long long inline int read() { int x=0,t=1;char ch=getchar(); while((ch<'0'||ch>'9')&&ch!='-'
)ch=getchar(); if(ch=='-')t=-1,ch=getchar(); while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar(); return x*t; } struct Line{int v,next,w,rt;}e[MAX<<1],E[MAX<<1]; int h[MAX],cnt=1; inline void Add(int u,int v,int w){e[cnt]=(Line){v,h[u],w,0};h[u]=cnt++;} int
H[MAX],Cnt=1; inline void ADD(int u,int v,int rt){E[Cnt]=(Line){v,H[u],0,rt};H[u]=Cnt++;} /************************************************************************/ int dfn[MAX],top[MAX],dep[MAX],ssize[MAX],hson[MAX],fa[MAX]; int dis[MAX]; void dfs1(int u,int ff) { fa[u]=ff;ssize[u]=1;dep[u]=dep[ff]+1; for(int i=h[u];i;i=e[i].next) { int v=e[i].v; if(v==ff)continue; dis[v]=dis[u]+e[i].w; dfs1(v,u); ssize[u]+=ssize[v]; if(ssize[hson[u]]<ssize[v])hson[u]=v; } } void dfs2(int u,int tp) { top[u]=tp; if(hson[u])dfs2(hson[u],tp); for(int i=h[u];i;i=e[i].next) { int v=e[i].v; if(v==fa[u]||v==hson[u])continue; dfs2(v,v); } } int LCA(int u,int v) { while(top[u]!=top[v]) { if(dep[top[u]]<dep[top[v]])swap(u,v); u=fa[top[u]]; } return dep[u]<dep[v]?u:v; } int Dis(int u,int v) { return dis[u]+dis[v]-dis[LCA(u,v)]*2; } /************************************************************************/ int sum[MAX],size[MAX],Fa[MAX]; int n,Q; ll td[MAX],tf[MAX]; int Size,root,minr; bool vis[MAX]; void Getroot(int u,int ff) { size[u]=1; int ret=0; for(int i=h[u];i;i=e[i].next) { int v=e[i].v; if(v==ff||vis[v])continue; Getroot(v,u); size[u]+=size[v]; ret=max(ret,size[v]); } ret=max(ret,Size-size[u]); if(ret<minr)minr=ret,root=u; } void DFS(int u,int ff) { vis[u]=true;Fa[u]=ff; for(int i=h[u];i;i=e[i].next) { int v=e[i].v; if(vis[v])continue; minr=n;Size=size[v]; Getroot(v,u); ADD(u,v,root); DFS(root,u); } } void Modify(int u,int w) { sum[u]+=w; for(int i=u;Fa[i];i=Fa[i]) { int dist=Dis(u,Fa[i]); sum[Fa[i]]+=w; td[Fa[i]]+=1ll*w*dist; tf[i]+=1ll*w*dist; } } ll Count(int u) { ll ret=td[u]; for(int i=u;Fa[i];i=Fa[i]) { int dist=Dis(u,Fa[i]); ret+=1ll*(sum[Fa[i]]-sum[i])*dist; ret+=td[Fa[i]]-tf[i]; } return ret; } ll Query(int u) { ll tmp=Count(u); for(int i=H[u];i;i=E[i].next) if(Count(E[i].v)<tmp)return Query(E[i].rt); return tmp; } int main() { n=read();Q=read(); for(int i=1,a,b,c;i<n;++i) { a=read(),b=read(),c=read(); Add(a,b,c),Add(b,a,c); } dfs1(1,0);dfs2(1,1); minr=Size=n;Getroot(1,0); int RT=root; DFS(root,0); while(Q--) { int u=read(),v=read(); Modify(u,v); printf("%lld\n",Query(RT)); } return 0; }

【BZOJ3924】幻想鄉戰略遊戲(動態點分治)