您的位置:首页 > 其它

bzoj3924 [Zjoi2015]幻想乡战略游戏(动态点分治)

2018-02-23 21:45 435 查看
就是求带权重心,可以修改点权。

我们首先建出重心树。对于每个节点x记

s1[x]–x的子树到x的答案,

s2[x]–x的子树的点权和,

s3[x]–x的子树到fa[x]的答案。

那我们就可以通过这些信息得出以x为重心的答案(在重心树上一直往上跳,复杂度O(log n).)

修改点权时,最多影响logn个点,我们就O(logn)的更新一下这些点的信息。

怎么找带权重心呢?从重心树的根开始,枚举它的所有出边(原树中的边),如果往那个方向走得到的答案更优,就走到那个方向的重心树中的儿子上去,否则最优的就是当前点了。(可以证明最多只有一个方向比我目前的点优,如果一个方向紧邻我的点的答案比我大,则这个方向的所有点的答案都肯定比我大。)

复杂度O(nlog2n∗20)O(nlog2n∗20)

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
#define ll long long
#define inf 0x3f3f3f3f
#define N 100010
inline char gc(){
static char buf[1<<16],*S,*T;
if(S==T){T=(S=buf)+fread(buf,1,1<<16,stdin);if(T==S) return EOF;}
return *S++;
}
inline int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
return x*f;
}
int n,m,fa
,sz
,f
,sumsz,rt,h
,num=0,root,dis
;
int dep
,mn[N<<1][20],dfn
,dfnum=0,Log[N<<1];
ll s1
,s2
,s3
;//s1[x]--x的子树到x的答案,s2[x]--x的子树的点权和,s3[x]--x的子树到fa[x]的答案
struct edge{
int to,next,val;
}data[N<<1];
bool vis
;
vector<int>son
,Gson
;
inline void dfs(int x,int Fa){
mn[++dfnum][0]=x;dfn[x]=dfnum;
for(int i=h[x];i;i=data[i].next){
int y=data[i].to;if(y==Fa) continue;
dep[y]=dep[x]+1;dis[y]=dis[x]+data[i].val;
dfs(y,x);mn[++dfnum][0]=x;
}
}
inline void inirmq(){
Log[0]=-1;
for(int i=1;i<=n<<1;++i) Log[i]=Log[i>>1]+1;
for(int i=1;i<=Log[n<<1];++i)
for(int j=1;j<=2*n-1;++j){
if(j+(1<<i-1)>2*n-1) break;
mn[j][i]=dep[mn[j][i-1]]<dep[mn[j+(1<<i-1)][i-1]]?mn[j][i-1]:mn[j+(1<<i-1)][i-1];
}
}
inline void dfs1(int x,int Fa){
sz[x]=1;
for(int i=h[x];i;i=data[i].next){
int y=data[i].to;if(vis[y]||y==Fa) continue;
dfs1(y,x);sz[x]+=sz[y];
}
}
inline void dfs2(int x,int Fa){
f[x]=0;
for(int i=h[x];i;i=data[i].next){
int y=data[i].to;if(vis[y]||y==Fa) continue;
dfs2(y,x);f[x]=max(f[x],sz[y]);
}f[x]=max(f[x],sumsz-sz[x]);if(f[x]<f[rt]) rt=x;
}
inline void getG(int x){
vis[x]=1;dfs1(x,0);
for(int i=h[x];i;i=data[i].next){
int y=data[i].to;if(vis[y]) continue;
sumsz=sz[y];rt=0;dfs2(y,0);fa[rt]=x;
son[x].push_back(y);Gson[x].push_back(rt);getG(rt);
}
}
inline int lca(int x,int y){
x=dfn[x],y=dfn[y];if(x>y) swap(x,y);
int t=Log[y-x+1];
return dep[mn[x][t]]<dep[mn[y-(1<<t)+1][t]]?mn[x][t]:mn[y-(1<<t)+1][t];
}
inline int caldis(int x,int y){
return dis[x]+dis[y]-2*dis[lca(x,y)];
}
inline void change(int x,int val){
for(int i=x;i;i=fa[i]){
s1[i]+=(ll)caldis(i,x)*val;
s2[i]+=val;
if(fa[i]) s3[i]+=(ll)caldis(x,fa[i])*val;
}
}
inline ll calc(int x){
ll res=s1[x];
for(int i=x;fa[i];i=fa[i]){
res+=s1[fa[i]]-s3[i]+(s2[fa[i]]-s2[i])*caldis(x,fa[i]);
}return res;
}
inline ll ask(int x){
ll res=calc(x);
for(int i=0;i<son[x].size();++i){
int y=son[x][i];
if(calc(y)<res) return ask(Gson[x][i]);
}return res;
}
int main(){
//  freopen("a.in","r",stdin);
n=read();m=read();f[0]=inf;
for(int i=1;i<n;++i){
int x=read(),y=read(),val=read();
data[++num].to=y;data[num].next=h[x];h[x]=num;data[num].val=val;
data[++num].to=x;data[num].next=h[y];h[y]=num;data[num].val=val;
}dfs(1,0);inirmq();
dfs1(1,0);sumsz=n;rt=0;dfs2(1,0);fa[rt]=0;root=rt;getG(rt);
while(m--){
int x=read(),val=read();
change(x,val);printf("%lld\n",ask(root));
}return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: