Bzoj3924--Fjoi2015幻想乡战略游戏

构造点分树,记录每个点管辖子树的大小Vc,这个点管辖子树内所有点到这个点的费用和Cos和这个子树对上一级重心费用的贡献Scos

每次修改直接点分树上修改

查询一个点,如果该点最大子树的大小大于全图一半,就把这个点除了最大子树外的部分贴到那个子树里对应的点上再递归去查询那个子树

如果最大子树也小于全图一半,那么这个点就是当前图的重心,答案就是Cos

代码 :

#include<bits/stdc++.h>
#define PA pair<int,int>
#define INF 0x3f3f3f3f
#define LL long long
using namespace std;

inline int _max(int a,int b) {return a>b?a:b;}

#define MAXN 100005

int n,m;

int head[MAXN],cnt;
struct Edge{
    int next,to,w;
}e[MAXN<<1];
inline void insert(int a,int b,int c) {
    e[++cnt].next=head[a];head[a]=cnt;e[cnt].to=b;e[cnt].w=c;
    e[++cnt].next=head[b];head[b]=cnt;e[cnt].to=a;e[cnt].w=c;
}

bool vis[MAXN];int sz[MAXN],weight[2];
void FindW(int v,int all) {
    vis[v]=1;sz[v]=0;int mx=0;
    for(int i=head[v];i;i=e[i].next) {
        if(!vis[e[i].to]) {
            FindW(e[i].to,all);
            mx=_max(mx,sz[e[i].to]);sz[v]+=sz[e[i].to];
        }
    }
    sz[v]++;mx=_max(mx,all-sz[v]);
    if(weight[0]>mx) weight[0]=mx,weight[1]=v;
    vis[v]=0;
}
int Anc[MAXN][26],Len[MAXN],To[MAXN],Tdis[MAXN];LL Dis[MAXN][26];
void Comp(int v,int anc,int d) {
    vis[v]=1;sz[v]=0;
    Anc[v][++Len[v]]=anc;Dis[v][Len[v]]=d;
    for(int i=head[v];i;i=e[i].next) {
        if(!vis[e[i].to]) {
            Comp(e[i].to,anc,d+e[i].w);
            sz[v]+=sz[e[i].to];
        }
    }
    sz[v]++;vis[v]=0;
}
void Solve(int w) {
    vis[w]=1;if(sz[w]==1) return;
    for(int i=head[w];i;i=e[i].next) {
        if(!vis[e[i].to]) {
            weight[0]=INF;FindW(e[i].to,sz[e[i].to]);
            To[weight[1]]=e[i].to;Tdis[weight[1]]=e[i].w;
            Comp(weight[1],weight[1],0);
            Solve(weight[1]);
        }
    }
}

LL Vc[MAXN],Cos[MAXN],Scos[MAXN],All;
inline void Modify(int x,int y) {
    All+=y;
    for(int i=Len[x];i;i--) {
        Vc[Anc[x][i]]+=y;
        Cos[Anc[x][i]]+=y*Dis[x][i];
        Scos[Anc[x][i]]+=y*Dis[x][i-1];
    }
}
void Change(int x,int sp,LL v,LL c,int fx) {
    for(int i=Len[x];i;i--) {
        if(Anc[x][i]==sp) return;
        Vc[Anc[x][i]]+=v;
        Cos[Anc[x][i]]+=v*(Dis[x][i]+fx)+c;
        Scos[Anc[x][i]]+=v*(Dis[x][i-1]+fx)+c;
    }
}
LL Query(int v,int d) {
    LL ans,go,s=0;
    for(int i=head[v];i;i=e[i].next)
        if(Anc[e[i].to][d]&&Vc[Anc[e[i].to][d]]>s) s=Vc[Anc[e[i].to][d]],go=Anc[e[i].to][d];
    if((s<<1)>All) {
        LL t=Vc[v]-Vc[go],c=Cos[v]-Scos[go];
        Change(To[go],v,t,c,Tdis[go]);
        ans=Query(go,d+1);
        Change(To[go],v,-t,-c,Tdis[go]);
        return ans;
    }
    else return Cos[v];
}

int main() {
    scanf("%d%d",&n,&m);
    for(int a,b,c,i=1;i<n;i++) {
        scanf("%d%d%d",&a,&b,&c);
        insert(a,b,c);
    }
    weight[0]=INF;FindW(1,n);
    Comp(weight[1],weight[1],0);
    Solve(weight[1]);
    for(int x,y,i=1;i<=m;i++) {
        scanf("%d%d",&x,&y);
        Modify(x,y);
        printf("%lld\n",Query(Anc[1][1],2));
    }
    return 0;
}
时间: 2024-08-07 15:28:14

Bzoj3924--Fjoi2015幻想乡战略游戏的相关文章

【BZOJ3924】幻想乡战略游戏(动态点分治)

[BZOJ3924]幻想乡战略游戏(动态点分治) 题面 权限题...(穷死我了) 洛谷 题解 考虑不修改 发现一个贪心的做法 假设当前放在当前位置 如果它有一个子树的兵的总数大于总数的一半 那么,放到那个子树的根节点上一定最优 那么,现在是动态修改 考虑动态点分治 在每个点上维护子树的兵的总数 子树到上一层父亲节点 向上走产生的贡献的总和 以及接收到子节点的贡献的总和 那么,就可以计算当前点产生的贡献 于是,从分治树根开始向下贪心即可 #include<iostream> #include&l

bzoj3924 [Zjoi2015]幻想乡战略游戏 点分树,动态点分

[BZOJ3924][Zjoi2015]幻想乡战略游戏 Description 傲娇少女幽香正在玩一个非常有趣的战略类游戏,本来这个游戏的地图其实还不算太大,幽香还能管得过来,但是不知道为什么现在的网游厂商把游戏的地图越做越大,以至于幽香一眼根本看不过来,更别说和别人打仗了. 在打仗之前,幽香现在面临一个非常基本的管理问题需要解决. 整个地图是一个树结构,一共有n块空地,这些空地被n-1条带权边连接起来,使得每两个点之间有一条唯一的路径将它们连接起来.在游戏中,幽香可能在空地上增加或者减少一些军

BZOJ3924 : [Zjoi2015]幻想乡战略游戏

对于一个点,要求出它到所有点的带权距离和,只需记录下树分治的结构然后查询即可. 修改$O(\log n)$,查询$O(\log n)$. 到所有点带权距离和最小的点显然是这棵树的带权重心. 以1号点为根,考虑一条从父亲x到孩子y的边: 若y子树内权值和>=总权值和-y子树内权值和,即2*y子树内权值和>=总权值和,则重心在y的子树里,否则不在. 所以重心一定是深度最大的满足2*子树内权值和>=总权值和的点. 可以发现重心及其祖先都满足2*子树内权值和>=总权值和,而这些点在DFS序

[ZJOI2015]幻想乡战略游戏 解题报告 (动态点分治)

[ZJOI2015]幻想乡战略游戏 题意 有一棵大小为 \(n\) 的带权树, 每个点有一个权值, 权值可以修改 \(q\) 次, 找出一个补给点 \(x\) , 使得 \(\sum_{u \in V} val[u] \times dis(x,u)\) 最小, 并求出这个最小值. 一句话 : 求带权重心 (zsy说的) 附加条件 : 树中所有点的度数不超过 \(20\). 思路 一道你以为复杂度过不了, 但其实是过得了的题. 首先, 我们假定先选了一个点 \(u\) 作为补给点, 我们可以算出它

BZOJ 3924 Zjoi2015 幻想乡战略游戏 动态树分治

题目大意:给定一棵树,每个点有一个点权,多次改变某个点的点权,多次查询带权重心到所有点的带权距离之和 此生无悔入东方,来世愿生幻想乡 首先我们考虑如何计算一个点到所有点的带权距离之和且支持修改 用动态树分治就好了嘛... 每个点记录子树中带权距离之和,以及权值之和,再在每个子树中记录一个需要减掉的版本 然后一直向上扫到根就能统计了 ↑这段话面对会写动态树分治的人,不会的先去切捉迷藏吧 然后就好搞了... 对于分治结构的每一个点,我们枚举它的出边 如果某条出边连向的点的距离之和小于当前点,那么答案

【bzoj3924】[Zjoi2015]幻想乡战略游戏 动态树分治

题目描述 傲娇少女幽香正在玩一个非常有趣的战略类游戏,本来这个游戏的地图其实还不算太大,幽香还能管得过来,但是不知道为什么现在的网游厂商把游戏的地图越做越大,以至于幽香一眼根本看不过来,更别说和别人打仗了. 在打仗之前,幽香现在面临一个非常基本的管理问题需要解决. 整个地图是一个树结构,一共有n块空地,这些空地被n-1条带权边连接起来,使得每两个点之间有一条唯一的路径将它们连接起来.在游戏中,幽香可能在空地上增加或者减少一些军队.同时,幽香可以在一个空地上放置一个补给站. 如果补给站在点u上,并

【bzoj3924&amp;&amp;luogu3345】幻想乡战略游戏

这题可以用线段树做,不过正解恐怕是动态点分治?(点分树) 简单介绍下动态点分治的概念:在点分治的过程中,一般我们面对的问题都是静态的.如果涉及到修改这类的操作,我们就希望找到我们是如何处理到当前的修改点的,换而言之,我们希望记录下点分治的过程,这样可以通过爬点分树等操作消除影响. 对于每个节点我们保存这个子树的dv的总和已经把该节点作为点的答案值 这样对于修改能在$O(logn)的时间内解决 简要看下题意:询问树的带权重心,加修改. 如果不加修改,找到树的重心就是一个树形dp的傻题. 寻找答案的

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

题目描述 傲娇少女幽香正在玩一个非常有趣的战略类游戏,本来这个游戏的地图其实还不算太大,幽香还能管得过来,但是不知道为什么现在的网游厂商把游戏的地图越做越大,以至于幽香一眼根本看不过来,更别说和别人打仗了. 在打仗之前,幽香现在面临一个非常基本的管理问题需要解决. 整个地图是一个树结构,一共有n块空地,这些空地被n-1条带权边连接起来,使得每两个点之间有一条唯一的路径将它们连接起来. 在游戏中,幽香可能在空地上增加或者减少一些军队.同时,幽香可以在一个空地上放置一个补给站. 如果补给站在点u上,

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

这种动态点分治嘛,GDKOI时听打到了,也有同学讲到了,所以印象比较深刻也就想出来了,然后就在实现方面卡了好久= = 不得不说CLJ说得真的太简单了,实现方面根本没提. 首先我们可以先用树分治构建出这棵树的分治树,也就是把这棵树的重心作为根节点然后子树为他的子树的重心这样递归下去,然后每个节点存的是其子树的信息. 对于每个节点我们保存这个子树的dv的总和已经把该节点作为点的答案值 这样对于修改能在log n的时间内解决 寻找答案的时候,我们可以发现,如果现在节点的子树dv和*2大于总节点,那么向