您的位置:首页 > 其它

bzoj3924 [Zjoi2015]幻想乡战略游戏

2018-02-24 23:20 127 查看
Description

傲娇少女幽香正在玩一个非常有趣的战略类游戏,本来这个游戏的地图其实还不算太大,幽香还能管得过来,但是不知道为什么现在的网游厂商把游戏的地图越做越大,以至于幽香一眼根本看不过来,更别说和别人打仗了。 在打仗之前,幽香现在面临一个非常基本的管理问题需要解决。 整个地图是一个树结构,一共有n块空地,这些空地被n-1条带权边连接起来,使得每两个点之间有一条唯一的路径将它们连接起来。在游戏中,幽香可能在空地上增加或者减少一些军队。同时,幽香可以在一个空地上放置一个补给站。 如果补给站在点u上,并且空地v上有dv个单位的军队,那么幽香每天就要花费dv×dist(u,v)的金钱来补给这些军队。由于幽香需要补给所有的军队,因此幽香总共就要花费为Sigma(Dv*dist(u,v),其中1<=V<=N)的代价。其中dist(u,v)表示u个v在树上的距离(唯一路径的权和)。 因为游戏的规定,幽香只能选择一个空地作为补给站。在游戏的过程中,幽香可能会在某些空地上制造一些军队,也可能会减少某些空地上的军队,进行了这样的操作以后,出于经济上的考虑,幽香往往可以移动他的补给站从而省一些钱。但是由于这个游戏的地图是在太大了,幽香无法轻易的进行最优的安排,你能帮帮她吗? 你可以假定一开始所有空地上都没有军队。

PDF版试题:JudgeOnline/upload/201708/zjoi2015d1.pdf

Input

第一行两个数n和Q分别表示树的点数和幽香操作的个数,其中点从1到n标号。

接下来n-1行,每行三个正整数a,b,c,表示a和b之间有一条边权为c的边。

接下来Q行,每行两个数u,e,表示幽香在点u上放了e单位个军队

(如果e<0,就相当于是幽香在u上减少了|e|单位个军队,说白了就是du←du+e)。

数据保证任何时刻每个点上的军队数量都是非负的。

1<=c<=1000, 0<=|e|<=1000, n<=10^5, Q<=10^5

对于所有数据,这个树上所有点的度数都不超过20

N,Q>=1

Output

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

Sample Input

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

Sample Output

0

1

4

5

6

我总觉得自己有种log^3的非常暴力的方法可以做 但是不知道能拿多少分就没写

照着icefox巨佬hnoi2015开点的动态点分方法写 常数巨大 优化了几次才勉强跑过去

之前在wc听课的时候讲随机化算法就看了jsoi的一道题 了解到带权重心一定在 当前点到某个权重更小的方向上 因为是保证这个度只有20 所以暴力转移即可 但是转移的话 为了复杂度有保证 选择在点分树上进行移动 下面考虑如何求出所有点到其中一个点的带权*距离

考虑到针对点分树 子树非常好做 子树外面的可以看作外面的点到子树的根即可

设s1[] s2[] 两个数组 分别表示 这个在点分树中的节点下所管辖的这个带权的距离是多少和在这个节点的管辖下 我的左右子树的这个带权距离是多少 近似于将s1数组向上平移

可以考虑看作先到根 在下到点分树 画图思考更加清晰啊

那么进行容斥的时候可以考虑我想要得到答案 需要计算点分树 的上几层的答案 考虑 首先我直接把上一层答案加上有什么影响 这样就多了我自己到上一层的那个距离了所以减去即可 然后继续容斥

lca的话 因为询问较多建议使用st表

#include<cstdio>
#include<algorithm>
#define ll long long
#define N 110000
#define inf 0x3f3f3f3f
using namespace std;
inline char gc(){
static char now[1<<16],*S,*T;
if (T==S){T=(S=now)+fread(now,1,1<<16,stdin);if (T==S) return EOF;}
return *S++;
}
inline int read(){
int x=0,f=1;char ch=gc();
while(ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=gc();}
while(ch<='9'&&ch>='0') x=x*10+ch-'0',ch=gc();
return x*f;
}
struct node{
int y,next,z;
}data[N<<1];
int fa
[30],dep
,Log[N<<1],fa1[N<<1],next[N<<1],root,sum,size
,f
,h
,n,m,num,tot1,pos
,mn[N<<1][60];
ll dis[N<<1],s1[N<<1],s2[N<<1],nm[N<<1];bool visit
;
inline void init(){
int t=Log[tot1];
for (int j=1;j<=t;++j){
for (int i=1;i<=tot1;++i){
if (i+(1<<j-1)>tot1) break;
if (dep[mn[i][j-1]]<dep[mn[i+(1<<j-1)][j-1]])
mn[i][j]=mn[i][j-1];else mn[i][j]=mn[i+(1<<j-1)][j-1];
}
}
}
inline void dfs(int x){
mn[++tot1][0]=x;pos[x]=tot1;
for (int i=h[x];i;i=data[i].next){
int y=data[i].y,z=data[i].z;if (y==fa[x][0]) continue;
dis[y]=dis[x]+z;fa[y][0]=x;dep[y]=dep[x]+1;dfs(y);mn[++tot1][0]=x;
}
}
inline int lca(int x,int y){
x=pos[x],y=pos[y];if (x>y) swap(x,y);int t=Log[y-x+1];
return dep[mn[x][t]]<dep[mn[y-(1<<t)+1][t]]?mn[x][t]:mn[y-(1<<t)+1][t];
}
inline ll dist(int x,int y){
return dis[x]+dis[y]-(dis[lca(x,y)]<<1);
}
inline void get_root(int x,int faf){
size[x]=1;f[x]=0;
for (int i=h[x];i;i=data[i].next){
int y=data[i].y;if (visit[y]||y==faf) continue;
get_root(y,x);size[x]+=size[y];f[x]=max(f[x],size[y]);
}f[x]=max(f[x],sum-size[x]);
if (f[root]>f[x]) root=x;
}
inline void solve(int x){
visit[x]=1;int sum1=sum;
for (int i=h[x];i;i=data[i].next){
int y=data[i].y;if (visit[y]) continue;
if (size[y]>size[x]) sum=sum1-size[x];else sum=size[y];
root=0;get_root(y,x);fa1[root]=x;next[i]=root;solve(root);
}
}
ll calc(int x){
ll tmp=0;
for (int i=x;i;i=fa1[i]) {
tmp+=s1[i]+nm[i]*dist(x,i);
if (fa1[i])tmp-=s2[i]+nm[i]*dist(x,fa1[i]);
}
return tmp;
}
int main(){
//  freopen("bzoj3924.in","r",stdin);
//  freopen("bzoj3924.out","w",stdout);
n=read();m=read();Log[0]=-1;for (int i=1;i<=n<<1;++i) Log[i]=Log[i>>1]+1;
for (int i=1;i<n;++i){
int x=read(),y=read(),z=read();
data[++num].y=y;data[num].z=z;data[num].next=h[x];h[x]=num;
data[++num].y=x;data[num].z=z;data[num].next=h[y];h[y]=num;
}dfs(1);root=0;f[0]=inf;sum=n;get_root(1,0);int rt=root;solve(root);init();
while(m--){
int x=read(),y=read();ll min1,tmp;
for (int i=x;i;i=fa1[i]) {
s1[i]+=y*dist(x,i),nm[i]+=y;
if (fa1[i])  s2[i]+=y*dist(x,fa1[i]);
}
x=rt;while(1){min1=calc(x);y=x;
for (int i=h[x];i;i=data[i].next){
if (!next[i]) continue;
if ((tmp=calc(data[i].y))<min1) min1=tmp,y=next[i];
}
if (x==y) {printf("%lld\n",min1);break;}
x=y;
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: