luogu P3345 [ZJOI2015]幻想乡战略游戏 |动态点分治

Posted naruto-mzx

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了luogu P3345 [ZJOI2015]幻想乡战略游戏 |动态点分治相关的知识,希望对你有一定的参考价值。

题目描述

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

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

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

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

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

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

输入格式

第一行两个数n和Q分别表示树的点数和幽香操作的个数,其中点从1到n标号。 接下来n-1行,每行三个正整数a,b,c,表示a和b之间有一条边权为c的边。 接下来Q行,每行两个数u,e,表示幽香在点u上放了e单位个军队(如果e<0,就相当于是幽香在u上减少了|e|单位个军队,说白了就是du←du+e)。数据保证任何时刻每个点上的军队数量都是非负的。

输出格式

对于幽香的每个操作,输出操作完成以后,每天的最小花费,也即如果幽香选择最优的补给点进行补给时的花费。


题解来自

建点分树,我们把点分治中每一个重心的父亲设为上一层的重心

每次查询只需要从根节点(整棵树的重心)开始,看哪一个(原树中)儿子更优,如果优就往儿子对应的子树的重心上走

再考虑修改,只用把自己在点分树中的祖先修改就行了

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define int long long
typedef long long LL;
template<typename T>inline void read(T &num) {
    char ch; int flg = 1;
    while((ch=getchar())<'0'||ch>'9')if(ch=='-')flg=-flg;
    for(num=0;ch>='0'&&ch<='9';num=num*10+ch-'0',ch=getchar());
    num*=flg;
}
const int MAXN = 100005;
int n, q, fir[MAXN], cnt;
struct edge { int to, nxt, w; }e[MAXN<<1];
inline void add(int u, int v, int wt) {
    e[cnt] = (edge){ v, fir[u], wt }, fir[u] = cnt++;
    e[cnt] = (edge){ u, fir[v], wt }, fir[v] = cnt++;
}
int dis[MAXN], son[MAXN], sz[MAXN], top[MAXN], fa[MAXN], dep[MAXN];
inline void dfs(int u, int ff) {
    dep[u] = dep[fa[u]=ff] + (sz[u]=1);
    for(int i = fir[u], v; ~i; i = e[i].nxt)
        if((v=e[i].to) != ff) {
            dis[v] = dis[u] + e[i].w;
            dfs(v, u), sz[u] += sz[v];
            if(sz[v] > sz[son[u]]) son[u] = v;
        }
}
inline void dfs2(int u,int tp){
    top[u]=tp;
    if(son[u])dfs2(son[u],tp);
    for(int i = fir[u], v; ~i; i = e[i].nxt)
        if((v=e[i].to) != fa[u] && v != son[u])
            dfs2(v,v);
}
inline 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;
}
inline int dist(int u,int v){
    return dis[u]+dis[v]-2*dis[lca(u,v)];
}
int Fa[MAXN],size[MAXN],Size,Minr,root,info[MAXN],CNT;
struct EDGE { int to, nxt, rt; }E[MAXN];
inline void ADD(int u,int v,int rr){
    E[CNT]=(EDGE){v,info[u],rr},info[u]=CNT++;
}
bool vis[MAXN];
void Getrt(int u, int ff) {
    size[u] = 1;
    int ret = 0;
    for(int i = fir[u], v; ~i; i = e[i].nxt)
        if((v=e[i].to) != ff && !vis[v]) {
            Getrt(v, u), size[u] += size[v];
            ret = max(ret, size[v]);
        }
    ret = max(ret, Size-size[u]);
    if(ret < Minr) Minr = ret, root = u;
}
inline void DFS(int u,int ff){
    vis[u]=1; Fa[u]=ff;
    for(int i = fir[u], v; ~i; i = e[i].nxt)
        if(!vis[v=e[i].to]) {
            Minr = n; Size = size[v];
            Getrt(v, u);
            ADD(u, v, root);
            DFS(root, u);
        }
}
LL sum[MAXN],sumd[MAXN],sumf[MAXN];
inline void Modify(int u,int val){
    sum[u]+=val;
    for(int i = u; Fa[i]; i = Fa[i]) {
        int len = dist(u, Fa[i]);
        sum[Fa[i]] += val;
        sumd[Fa[i]] +=val * len;
        sumf[i] +=val * len;
    }
}
inline LL Count(int u){
    LL res=sumd[u];
    for(int i=u;Fa[i];i=Fa[i]){
        int len=dist(u,Fa[i]);
        res+=(sum[Fa[i]]-sum[i])*len;
        res+=(sumd[Fa[i]]-sumf[i]);
    }
    return res;
}
inline LL Query(int u) {
    LL tmp = Count(u);
    for(int i = info[u]; ~i; i = E[i].nxt)
        if(Count(E[i].to) < tmp) return Query(E[i].rt);
    return tmp;
}
signed main(){
    memset(fir, -1, sizeof fir); memset(info, -1, sizeof info);
    read(n), read(q);
    for(int i = 1, x, y, z; i < n; ++i) read(x), read(y), read(z), add(x, y, z);
    dfs(1, 0), dfs2(1, 1);
    Size = Minr = n; Getrt(1, 0);
    int RT = root; 
    DFS(root, 0);
    int x, y;
    while(q--) {
        read(x), read(y);
        Modify(x, y);
        printf("%lld
", Query(RT));
    }
}

以上是关于luogu P3345 [ZJOI2015]幻想乡战略游戏 |动态点分治的主要内容,如果未能解决你的问题,请参考以下文章

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

P3345 [ZJOI2015]幻想乡战略游戏

P3345 [ZJOI2015]幻想乡战略游戏

并不对劲的bzoj3924:loj2135:p3345:[ZJOI2015]幻想乡战略游戏

[Luogu3345][ZJOI2015]幻想乡战略游戏

Luogu3346 [ZJOI2015]诸神眷顾的幻想乡