[ZJOI2015] 幻想乡战略游戏

[ZJOI2015] 幻想战略游戏(树链剖分 + 线段树二分 + 带权重心) 点分治不可能这一辈子都不可能,高举我树剖大旗! 阅读详情
P3254【ZJOI2015 Day1】幻想乡战略游戏
时间限制 : 120000 MS   空间限制 : 512000 KB
问题描述

        傲娇少女幽香正在玩一个非常有趣的战略类游戏,本来这个游戏的地图其实还不算太大,幽香还能管得过来,但是不知道为什么现在的网游厂商把游戏的地图越做越大,以至于幽香一眼根本看不过来,更别说和别人打仗了。
        在打仗之前,幽香现在面临一个非常基本的管理问题需要解决。
        整个地图是一个树结构,一共有n块空地,这些空地被n-1条带权边连接起来,使得每两个点之间有一条唯一的路径将它们连接起来。在游戏中,幽香可能在空地上增加或者减少一些军队。同时,幽香可以在一个空地上放置一个补给站。
        如果补给站在点u上,并且空地v上有dv个单位的军队,那么幽香每天就要花费dv×dist(u,v)的金钱来补给这些军队。由于幽香需要补给所有的军队,因此幽香总共就要花费的代价。其中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)。数据保证任何时刻每个点上的军队数量都是非负的。


输出格式

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

样例输入

10 5
1 2 1
2 3 1
2 4 1
1 5 1
2 6 1
2 7 1
5 8 1
7 9 1
1 10 1
3 1
2 1
8 1
3 1
4 1

样例输出

0
1
4
5
6

提示

        对于所有数据,1<=c<=1000, 0<=|e|<=1000, n<=105, Q<=105。
        对于15%的数据:n<=5000, Q<=2000。
        另有10%的数据:这个树的结构是一条链。
        另有5%的数据:这个树是随机生成的,生成方法为对于每个点i>1,在<i的点中随机一个作为它的父亲。
        另有5%的数据:这个树的结构是一个十字(即两条链通过一个公共点相交,例子见下图)。

     另有5%的数据,这棵树的结构是一个以1号节点为根的完全二叉树,并且标号方法与二叉堆相同(我相信大家都知道什么是完全二叉树,就不说明了)。
        另有30%的数据,幽香只会增加军队(所有e>=0)。
        非常神奇的是,对于所有数据,这棵树所有节点的度数都不超过20,并且n,Q>=1。

题解:
首先,这个题有比正解快得多的暴力做法,每次暴力更新带权重心,不知道比正解快到哪里去了。
说正解,每个点维护3个值(以下所说的父子关系均为重构的重心树的父子关系)
sum[x]:子树中d之和
ans[x]:子树中所有点的人到x的距离和,∑d(u)*dis(u,x)
ans_f[x]:子树中所有点的人到fa[x]的距离和,∑d(u)*dis(u,fa[x])
每次修改,沿着重心树往上走,更新维护的三个值
查答案比较迷,从重心树的根节点开始查,走原图上的边,若更优,就跳到该点所在块的下一层重心处继续查。若没有更优的,他自己就是答案了
#include<cstdio>  
#include<iostream>  
#include<cstdlib>  
#include<algorithm>  
#include<vector> 
#include<cstring>  
#include<cmath> 
#define pii pair<int,int> 
#define xx first 
#define yy second 
#define mp make_pair 
#define ll long long  
using namespace std;  
const int inf=0x3f3f3f3f;  
template <typename T>  
inline void _read(T& x){  
    char t=getchar();bool sign=true;  
    while(t<'0'||t>'9'){if(t=='-')sign=false;t=getchar();}  
    for(x=0;t>='0'&&t<='9';t=getchar())x=x*10+t-'0';  
    if(!sign)x=-x;  
} 
int n,m,e,tot,vistime,root; 
struct line{ 
    int from,to,len; 
    line(){}
    line(int x,int y,int z){from=x;to=y;len=z;} 
}; 
line edge[2000005]; 
int last[1000005],_next[2000005]; 
void add_edge(int x,int y,int z){ 
    edge[++e]=line(x,y,z); 
    _next[e]=last[x]; 
    last[x]=e; 
} 
int q[1000005],fa[1000005],size[1000005],maxsize[1000005],log_2[1000005]; 
bool del[1000005]; 
vector<pii> link[1000005]; 
void DFS(int x,int FA){ 
    int i,j,k,v; 
    q[++vistime]=x; 
    maxsize[x]=size[x]=1; 
    for(i=last[x];i;i=_next[i]){ 
        int v=edge[i].to; 
        if(v==FA||del[v])continue; 
        DFS(v,x); 
        size[x]+=size[v]; 
        maxsize[x]=max(maxsize[x],size[v]); 
    } 
} 
int focus(int x){ 
    int i,j,k,temp=0,minn=inf; 
    vistime=0; 
    DFS(x,0); 
    for(i=1;i<=vistime;i++){ 
        maxsize[q[i]]=max(maxsize[q[i]],size[x]-size[q[i]]); 
        if(maxsize[q[i]]<minn){ 
            minn=maxsize[q[i]]; 
            temp=q[i]; 
        } 
    } 
    return temp; 
} 
int build_new_tree(int x,int FA){ 
    int i,j,k,v; 
    x=focus(x); 
    del[x]=true;fa[x]=FA; 
    for(i=last[x];i;i=_next[i]){ 
        v=edge[i].to; 
        if(del[v])continue; 
        int tp=build_new_tree(v,x); 
        link[x].push_back(mp(v,tp)); 
    } 
    return x; 
} 


ll f[1000005][25],dist[1000005],id[1000005]; 
void dfs(int x,int FA){ 
    int i,j,k,v; 
    q[id[x]=++vistime]=x; 
    for(i=last[x];i;i=_next[i]){ 
        v=edge[i].to; 
        if(v==FA)continue; 
        dist[v]=dist[x]+edge[i].len; 
        dfs(v,x); 
        q[++vistime]=x; 
    } 
} 
ll dis(int x,int y){ 
    ll temp=dist[x]+dist[y]; 
    x=id[x];y=id[y]; 
    if(x>y)swap(x,y); 
    int k=log_2[y-x+1]; 
    ll d=min(f[y][k],f[x-1+(1<<k)][k]); 
    return temp-(d<<1); 
} 

ll sum[1000005],ans[1000005],ans_f[1000005]; 
ll query(int x){ 
    int temp=x; 
    ll ret1=ans[x],ret2; 
    while(true){ 
        if(fa[temp]==0)return ret1; 
        ret2=ans[fa[temp]]-ans_f[temp]; 
        ret1+=ret2+(sum[fa[temp]]-sum[temp])*dis(x,fa[temp]); 
        temp=fa[temp]; 
    }
}
void change(int x,int d){ 
    int temp=x; 
    while(true){ 
        sum[temp]+=d; 
        ans[temp]+=dis(x,temp)*d; 
        if(fa[temp]){ 
            ans_f[temp]+=dis(x,fa[temp])*d; 
            temp=fa[temp]; 
        } 
        else return; 
    } 
} 
ll getans(){ 
    int temp=root,i; 
    ll ansnow,ansson,tempson; 
    pii pos; 
    while(true){ 
    	ansnow=ansson=query(temp);
        for(i=0;i<link[temp].size();i++){
            tempson=query(link[temp][i].xx);
            if(tempson<ansson){ 
                ansson=tempson; 
                pos=link[temp][i]; 
            } 
        } 
        if(ansson!=ansnow){ 
            temp=pos.yy; 
        } 
        else return ansnow; 
    } 
} 

int main_main(){
    int i,j,k; 
    cin>>n>>m; 
    for(i=1;i<n;i++){
        int x,y,z; 
        _read(x);_read(y);_read(z); 
        add_edge(x,y,z);add_edge(y,x,z); 
    } 
    build_new_tree(1,0);
    vistime=0;
    dfs(1,0); 
    log_2[1]=0;
	int cc=0; 
    for(i=2;i<=vistime;i++){
        log_2[i]=cc; 
        if((1<<(cc+1))==i)cc++; 
    }
    for(i=1;i<=vistime;i++){
        f[i][0]=dist[q[i]]; 
    } 
    for(j=1;j<=18;j++){ 
        for(i=(1<<j);i<=vistime;i++){
            f[i][j]=min(f[i][j-1],f[i-(1<<(j-1))][j-1]); 
        } 
    } 
    root=1;
    while(fa[root])root=fa[root]; 
    while(m--){ 
        int x,y; 
        _read(x);_read(y); 
        change(x,y); 
        printf("%lld\n",getans()); 
    } 
}
const int main_stack=16;  
char my_stack[128<<20];  
int main() {  
  __asm__("movl %%esp, (%%eax);\n"::"a"(my_stack):"memory");  
  __asm__("movl %%eax, %%esp;\n"::"a"(my_stack+sizeof(my_stack)-main_stack):"%esp");  
  main_main();  
  __asm__("movl (%%eax), %%esp;\n"::"a"(my_stack):"%esp");  
  return 0;  
} 






ZJOI2015幻想战略游戏【点分树】【带权重心】 题意:nnn个点带边权的树,动态修改点权viv_ivi​,最小化 钦定一个点xxx 后 ∑idist(x,i)∗vi\sum\limits_{i} dist(x,i)*v_ii∑​dist(x,i)∗vi​的值。 n,q≤105n,q \leq10^5n,q≤105,度数不超过202020 限制度数的树上的一些诡异的操作,时限很长,多半是点分树。 也叫动态点分治,但实际上并不是动态的点分治并且有一... 阅读详情

相关推荐

[ZJOI2015] 幻想战略游戏——树链剖分

1e5 的 O(n log^3 n) 竟然只跑了100ms!

偶耶的博客 3757

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

就是求带权重心,可以修改点权。 我们首先建出重心树。对于每个节点x记 s1[x]–x的子树到x的答案, s2[x]–x的子树的点权和, s3[x]–x的子树到fa[x]的答案。 那我们就可以通过这些信息得出以x为重心的答案(在重心树上一直往上跳,复杂度O(log n).) 修改点权时,最多影响logn个点,我们就O(logn)的更新一下这些点的信息。 怎么找带权重心呢?从重心树的根开...

Icefox的博客 633

[ZJOI2015]幻想战略游戏

题目大意一个nn个节点的树,点带有权值dd,边也带有权值(小于等于10001000的正整数)。初始时点权为00。 定义dist(u,v)dist(u,v)为uu与vv两点之间简单路径的边权和。 会有QQ次操作,形如: ∙u e\bullet u\ e,表示dud_u加上e(0≤|e|≤1000)e(0\le|e|\le1000) 每次操作之后,你都需要找到一个点xx,最小化 w=∑i=1n

待成熟的葡萄 2209

Luogu3345 [ZJOI2015]幻想战略游戏

Luogu3345 [ZJOI2015]幻想战略游戏 题面:良心洛谷 解析 动态点分治。假定我们已经确定了补给点,可以通过在点分树上\(O(logn)\)统计答案,修改亦可\(O(logn)\)做到,具体的话就是维护一下当前重心\(w\)的\(\sum_{v} d_v\)与\(\sum_{v} d_vdist(v,w)\),在多维护一个父节点信息,容斥即可。现在考虑如何确定补给点?还是...

192

ZJOI2015 幻想战略游戏 动态点分治_树链剖分_未调完

ZJOI2015 幻想战略游戏 动态点分治_树链剖分_未调完 最近写动态点分治快自闭了QAQ....... 有时间再来写一下题解. 其实我不会告诉你我还没调出来呢QAQ Code: // luogu-judger-enable-o2 // luogu-judger-enable-o2 #include <bits/...

EM LGH 132

BZOJ3924: [Zjoi2015]幻想战略游戏

BZOJ3924: [Zjoi2015]幻想战略游戏 https://lydsy.com/JudgeOnline/problem.php?id=3924 分析: 首先有一个很棒的思路,就是在点分树上跳重心,每次向答案最小的子分治中心移动。 这个是对的,因为树上带权重心往旁边的点走答案一定更差。 只需要每次能够\(O(logn)​\)查询即可,维护点分树上子树\(dist\times ...

132

P3345 [ZJOI2015]幻想战略游戏

P3345 [ZJOI2015]幻想战略游戏 带修改带权重心 这是经典的树上寻找关键点的题目,我们使用点分治处理这个问题,因为点分治的特性,就相当于在树上二分了。但是这与倍增不同,倍增只是在链上二分,而点分治则是在整棵树上二分。 然后我们考虑如何二分,显然带权重心的位置和边权无关,并且每次只需要寻找一个点的2sumv>sumu2sum_v>sum_u2sumv​>sumu​那么重心一定在这个子树内部。也就是说有一个儿子的答案比当前点小,那么重心就在这个子树内。我们可以维护3个变量。 su

xajd1906的博客 206

[ZJOI2015]幻想战略游戏——动态点分治

[ZJOI2015]幻想战略游戏 带修改下,边点都带权的重心随着变动的过程中,一些子树内的点经过会经过一些公共边。考虑能不能对这样的子树一起统计。把树上贡献分块。考虑点分治算法不妨先把题目简化一下:假设没有修改,多次询问,每次给定一个s,求$\sum d_v*dis(s,v)$为了让一块可以一起统计,我们设:$sum[x]:$x为根的点分治树管辖部分的权值和$df[x]$:x为根的点分治树管辖...

weixin_34355559的博客 135

洛谷 P3345 [ZJOI2015]幻想战略游戏 解题报告

P3345 [ZJOI2015]幻想战略游戏 题目描述 傲娇少女幽香正在玩一个非常有趣的战略游戏,本来这个游戏的地图其实还不算太大,幽香还能管得过来,但是不知道为什么现在的网游厂商把游戏的地图越做越大,以至于幽香一眼根本看不过来,更别说和别人打仗了。 在打仗之前,幽香现在面临一个非常基本的管理问题需要解决。 整个地图是一个树结构,一共有\(n\)块空地,这些空地被\(n-1\)条带权边连接起来...

weixin_30273501的博客 173

[zjoi2015]幻想战略游戏

前言 略略略 题目相关 链接 题目大意 给出一棵树,每次修改一个点的权值,维护一个带权重心 啥是带权重心? 设点iii的值为ViV_iVi​我们要选一个点uuu,每个点对应一个值: ∑v=1nVv∗dis(u,v)\sum_{v=1}^n V_v*dis(u,v)v=1∑n​Vv​∗dis(u,v) 我们要选一个uuu使得这个值最小 输出最小的值 数据范围 n,q≤105n,q\le10^5n,q...

zhouyuheng2003的博客 647

BZOJ3924 ZJOI2015 幻想战略游戏 【动态点分治】

BZOJ3924 ZJOI2015 幻想战略游戏 Description 傲娇少女幽香正在玩一个非常有趣的战略游戏,本来这个游戏的地图其实还不算太大,幽香还能管得过来,但是不知道为什么现在的网游厂商把游戏的地图越做越大,以至于幽香一眼根本看不过来,更别说和别人打仗了。 在打仗之前,幽香现在面临一个非常基本的管理问题需要解决。 整个地图...

weixin_30319153的博客 82

AC日记——[ZJOI2015]幻想战略游戏 洛谷 P3345

[ZJOI2015]幻想战略游戏 思路:   树剖暴力转移; 代码: #include <bits/stdc++.h> using namespace std; #define maxn 100005 #define ll long long struct TreeNodeType { ll l,r,sum,mid; }; struct ...

weixin_30911451的博客 70
上一篇: [ZJOI2015] 地震后的幻想乡
下一篇: [ZJOI2015] 诸神眷顾的幻想乡
INCINCIBLE
博客等级 码龄11年 31粉丝 195原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值