[ZJOI2015]幻想乡战略游戏

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 61
2 7 1
5 8 1
7 91
1 10 1
3 1
2 1
8 1
3 1
4 1

Sample Output

0
1
4
5
6
先假设1为补给站
那么相邻节点x满足军队数s[x]>=w-s[x]
那么把补给站移到x显然更好,因为减少的比增加的人多
也就是说,在满足2*s[x]>=w的情况下,尽量往下走
也就是找到满足条件dfs序编号最大的
ans(x)=∑d[i]dist(i,x)=∑d[i](dep[i]+dep[x]-2*dep[lca])
=∑d[i]dep[i]+∑d[i]dep[x]-2*∑d[i]dep[lca]
前两个不用管,最后一个可以这样:
给u加e的军队,那么就给1~u都加上e,查询时查询1~x的路径和
这样就等于答案加上了e*dep[lca]
用树链剖分+线段树维护区间和,最大值和延迟标记
  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 #include<cmath>
  6 using namespace std;
  7 typedef long long lol;
  8 struct Node
  9 {
 10   int next,to;
 11   lol dis;
 12 }edge[200001];
 13 int num,head[100001],size[100001],fa[100001],son[100001];
 14 int top[100001],dfn[100001],id[100001],cnt,n,Q;
 15 lol lazy[400001],c[400001],mx[400001],s[400001],dep[100001];
 16 void add(int u,int v,lol w)
 17 {
 18   num++;
 19   edge[num].next=head[u];
 20   head[u]=num;
 21   edge[num].to=v;
 22   edge[num].dis=w;
 23 }
 24 void dfs1(int x,int pa)
 25 {int i;
 26   size[x]=1;
 27   for (i=head[x];i;i=edge[i].next)
 28     {
 29       int v=edge[i].to;
 30       if (v!=pa)
 31     {
 32       fa[v]=x;
 33       dep[v]=dep[x]+edge[i].dis;
 34       dfs1(v,x);
 35       size[x]+=size[v];
 36       if (size[v]>size[son[x]]) son[x]=v;
 37     }
 38     }
 39 }
 40 void dfs2(int x,int pa,int tp)
 41 {int i;
 42   top[x]=tp;
 43   dfn[x]=++cnt;id[cnt]=x;
 44   if (son[x]) dfs2(son[x],x,tp);
 45   for (i=head[x];i;i=edge[i].next)
 46     {
 47       int v=edge[i].to;
 48       if (v==son[x]||v==pa) continue;
 49       dfs2(v,x,v);
 50     }
 51 }
 52 void pushdown(int rt,int l,int r)
 53 {
 54   int mid=(l+r)/2;
 55   if (lazy[rt])
 56     {
 57       int ls=rt<<1,rs=ls+1;
 58       c[ls]+=s[ls]*lazy[rt];
 59       lazy[ls]+=lazy[rt];
 60       mx[ls]+=lazy[rt];
 61       c[rs]+=s[rs]*lazy[rt];
 62       lazy[rs]+=lazy[rt];
 63       mx[rs]+=lazy[rt];
 64       lazy[rt]=0;
 65     }
 66 }
 67 void pushup(int rt)
 68 {
 69   mx[rt]=max(mx[rt<<1],mx[rt<<1|1]);
 70   c[rt]=c[rt<<1]+c[rt<<1|1];
 71 }
 72 void build(int rt,int l,int r)
 73 {
 74   if (l==r)
 75     {
 76       s[rt]=dep[id[l]]-dep[fa[id[l]]];
 77       return;
 78     }
 79   int mid=(l+r)/2;
 80   build(rt<<1,l,mid);
 81   build(rt<<1|1,mid+1,r);
 82   s[rt]=s[rt<<1]+s[rt<<1|1];
 83 }
 84 void update(int rt,int l,int r,int L,int R,lol d)
 85 {
 86   if (l>=L&&r<=R)
 87     {
 88       c[rt]+=s[rt]*d;
 89       lazy[rt]+=d;
 90       mx[rt]+=d;
 91       return;
 92     }
 93   int mid=(l+r)/2;
 94   pushdown(rt,l,r);
 95   if (L<=mid) update(rt<<1,l,mid,L,R,d);
 96   if (R>mid) update(rt<<1|1,mid+1,r,L,R,d);
 97   pushup(rt);
 98 }
 99 lol query(int rt,int l,int r,int L,int R)
100 {
101   if (l>=L&&r<=R)
102     {
103       return c[rt];
104     }
105   int mid=(l+r)/2;
106   lol sum=0;
107   pushdown(rt,l,r);
108   if (L<=mid) sum+=query(rt<<1,l,mid,L,R);
109   if (R>mid) sum+=query(rt<<1|1,mid+1,r,L,R);
110   pushup(rt);
111   return sum;
112 }
113 void change(int x,lol d)
114 {
115   while (x)
116     {
117       update(1,1,n,dfn[top[x]],dfn[x],d);
118       x=fa[top[x]];
119     }
120 }
121 lol ask(int x)
122 {
123   lol sum=0;
124     while (x)
125     {
126       sum+=query(1,1,n,dfn[top[x]],dfn[x]);
127       x=fa[top[x]];
128     }
129     return sum;
130 }
131 int take(int rt,int l,int r,int x)
132 {
133   if (l==r) return l;
134   int mid=(l+r)/2;
135   pushdown(rt,l,r);
136   if (mx[rt<<1|1]>=x) return take(rt<<1|1,mid+1,r,x);
137   return take(rt<<1,l,mid,x);
138 }
139 int find(int x)
140 {
141   return take(1,1,n,x);
142 }
143 int main()
144 {int i,u,v,x;
145   lol w,sx,e;
146   cin>>n>>Q;
147   for (i=1;i<=n-1;i++)
148     {
149       scanf("%d%d%lld",&u,&v,&w);
150       add(u,v,w);add(v,u,w);
151     }
152   dfs1(1,0);
153   dfs2(1,0,1);
154   build(1,1,n);
155   w=0;
156   sx=0;
157   while (Q--)
158     {
159       scanf("%d%lld",&u,&e);
160       change(u,e);
161       sx+=dep[u]*e;
162       w+=e;
163       x=id[find(w+1>>1)];
164       printf("%lld\n",sx+w*dep[x]-2*ask(x));
165     }
166 }
View Code线段树
posted @ 2018-01-23 15:38  Z-Y-Y-S  阅读(349)  评论(0编辑  收藏  举报