您的位置:首页 > 其它

[ZJOI2015] 幻想乡战略游戏

2017-04-25 11:13 281 查看
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;
}


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: