• luogu_P3345[zjoi2015]幻想乡战略游戏


    传送门

    Description

    傲娇少女幽香正在玩一个非常有趣的战略类游戏,本来这个游戏的地图其实还不算太大,幽香还能管得过来,但是不知道为什么现在的网游厂商把游戏的地图越做越大,以至于幽香一眼根本看不过来,更别说和别人打仗了。

    在打仗之前,幽香现在面临一个非常基本的管理问题需要解决。 整个地图是一个树结构,一共有(n)块空地,这些空地被(n-1)条带权边连接起来,使得每两个点之间有一条唯一的路径将它们连接起来。

    在游戏中,幽香可能在空地上增加或者减少一些军队。同时,幽香可以在一个空地上放置一个补给站。 如果补给站在点(u)上,并且空地v上有(dv)个单位的军队,那么幽香每天就要花费(dv*dist(u,v))的金钱来补给这些军队。

    由于幽香需要补给所有的军队,因此幽香总共就要花费为(sum Dv*dist(u,v)) ((1leq V leq N))的代价。其中(dist(u,v))表示u个v在树上的距离(唯一路径的权和)。

    因为游戏的规定,幽香只能选择一个空地作为补给站。在游戏的过程中,幽香可能会在某些空地上制造一些军队,也可能会减少某些空地上的军队,进行了这样的操作以后,出于经济上的考虑,幽香往往可以移动他的补给站从而省一些钱。

    但是由于这个游戏的地图是在太大了,幽香无法轻易的进行最优的安排,你能帮帮她吗? 你可以假定一开始所有空地上都没有军队。

    Solution

    题意:树上点权修改,询问带权重心

    大大加深了对点分树的理解?

    首先,点分树有个性质:点分树上的两点的lca在原树的两点路径上,这样,我们通过记录点分树上一点到它的祖先的在原树上的距离,就可以得到任意两点在原树上的距离啦

    带权重心是什么咧?

    可以当做它是这样一个点,已这个点为根的每个子树的权重都不超过原树的总size的一半。

    为什么?假如找到了这个点,那么无论把它移动进入哪个子树,代价都会变得更大,读者可以自行证明。

    而我们用上面的做法,就可以得到树的带权重心。

    对于这道题:

    • 先预处理出点分树,记录下每个点在点分树上的孩子和祖先以及和每个祖先的实际距离(便于以后查找)

    • 记录下点分树上每个节点,在原树上所代表的联通块的根节点(HR)(这里指的是深度最小的那个点)

      为什么要记录这个东西咧?

      因为我们在寻找带权重心的时候,每进入一个点,就要更改某些点的权重,因为要算上除了这个联通块外的权重,而需要更改的点就是这个(HR),可以理解为,它是这个联通块的边界

      当然找到重心后,你得把你做的更改全都改回来

    • 我们考虑每次更改会有什么影响,首先,总权重增加(e),点分树上的相关节点的总权重也会发生变化,还有就是要即使更新相关节点的代价和,具体的,加上(e*dis),这里的相关节点指的是修改节点的祖先节点(我们显然只需要记录它对祖先的贡献,根据点分树的性质)

    • 查询就是枚举这个点与重心的在点分树上的(lca),统计代价即可

    因为点分树的深度不超过(log n),所以总复杂度是(O(n log^2 n))


    Code 

    #include<bits/stdc++.h>
    #define ll long long
    #define max(a,b) ((a)>(b)?(a):(b))
    #define min(a,b) ((a)<(b)?(a):(b))
    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<<3)+(x<<1)+ch-'0';ch=getchar();}
    	return x*f;
    }
    #define MN 100005
    #define reg register
    int n,m,en,hr[MN];
    struct edge{int to,w,nex;}e[MN<<1];
    inline void ins(int f,int t,int w)
    {
    	e[++en]=(edge){t,w,hr[f]};hr[f]=en;
    	e[++en]=(edge){f,w,hr[t]};hr[t]=en;
    }
    bool vis[MN];
    int rt,sm,siz[MN],dep[MN];
    ll vsum,w[MN],val[MN];
    struct Node{int id;ll dis;};
    std::vector<Node> fa[MN],s[MN];
    int HR[MN];
    void pre_dfs(int x,int f)
    {
    	reg int i;siz[x]=1;
    	for(i=hr[x];i;i=e[i].nex)if(!vis[e[i].to]&&(f^e[i].to))
    		pre_dfs(e[i].to,x),siz[x]+=siz[e[i].to];
    }
    void getroot(int x,int f)
    {
    	reg int i;rt=x;
    	for(i=hr[x];i;i=e[i].nex)
    	if(!vis[e[i].to]&&(f^e[i].to)&&(siz[e[i].to]<<1)>=sm){getroot(e[i].to,x);break;}
    }
    void dfs(int x,int f,int ro)
    {
    	fa[x].push_back((Node){ro,dep[x]});
    	reg int i;
    	for(i=hr[x];i;i=e[i].nex)if(!vis[e[i].to]&&(f^e[i].to))
    		dep[e[i].to]=dep[x]+e[i].w,dfs(e[i].to,x,ro);
    }
    inline void pre_work(int x=1,int f=0)
    {
    	pre_dfs(x,f);
    	sm=siz[x];getroot(x,f);vis[rt]=true;
    	reg int i,j=rt;
    	s[f].push_back((Node){j,0LL});fa[j].push_back((Node){j,0LL});
    	HR[j]=x;
    	for(i=hr[rt];i;i=e[i].nex)
    		if(!vis[e[i].to]){dep[e[i].to]=e[i].w;dfs(e[i].to,j,j);pre_work(e[i].to,j);}
    	rt=j;
    }
    inline void Modify(int x,int y)
    {
    	vsum+=y;val[x]+=y;reg int i,j=x,f,k;
    	for(i=fa[x].size()-1;~i;--i) w[fa[x][i].id]+=y;
    	for(i=fa[x].size()-2;~i;--i)
    		for(j=s[fa[x][i].id].size()-1;~j;--j)
    		if(s[fa[x][i].id][j].id==fa[x][i+1].id){s[fa[x][i].id][j].dis+=y*fa[x][i].dis;break;}
    }
    inline void upd(int x,int y){for(reg int i=fa[x].size()-1;~i;--i)w[fa[x][i].id]+=y;}
    inline int Find(int x)
    {
        reg int ret=x,i,tmp;
        for(i=s[x].size()-1;~i;--i)
            if(w[s[x][i].id]*2>=vsum)
            {
                tmp=w[x]-w[s[x][i].id];
                upd(HR[s[x][i].id],tmp);ret=Find(s[x][i].id);upd(HR[s[x][i].id],-tmp);
    			break;
            }
    	return ret;
    }
    inline ll Query(int x)
    {
        reg ll ret=0;
    	reg int i,j,las=0;
        for(i=fa[x].size()-1;~i;las=fa[x][i].id,--i)
        {
            ret+=fa[x][i].dis*val[fa[x][i].id];
            for(j=s[fa[x][i].id].size()-1;~j;--j)
                if(s[fa[x][i].id][j].id^las)
    				ret+=fa[x][i].dis*w[s[fa[x][i].id][j].id]+s[fa[x][i].id][j].dis;
        }
    	return ret;
    }
    int main()
    {
    	n=read();m=read();
    	register int i,x,y;
        for(i=1;i<n;++i) x=read(),y=read(),ins(x,y,read());
        pre_work();
        while(m--)
        {
        	x=read();y=read();Modify(x,y);
        	printf("%lld
    ",Query(Find(rt)));
    	}
    	return 0;
    }
    


    Blog来自PaperCloud,未经允许,请勿转载,TKS!

  • 相关阅读:
    关于xampp 集成开发包电脑重启mysql无法启动的问题
    ThinkPhP html原样入库
    java 获取图片大小(尺寸)
    xampps 不能配置非安装目录虚拟主机解决方案
    从0开始 java 网站开发(jsp)【1】
    Hello world!
    SpringMVC归纳-1(model数据模型与重定向传参技术)
    TTL与非门电路分析
    git入门手册:git的基本安装,本地库管理,远程上传
    实现简单的评论区功能
  • 原文地址:https://www.cnblogs.com/PaperCloud/p/10213065.html
Copyright © 2020-2023  润新知