zoukankan      html  css  js  c++  java
  • [ZJOI 2015]幻想乡战略游戏

    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

    题解

    其实和[HNOI 2015]开店的动态点分统计答案的方法类似,不再赘述。

    这里主要讲如何找到“带权重心”。

    我们每次从点分的根开始遍历与它相邻的所有点,统计出他们的答案,值得肯定的是这些值只会存在两种情况:

    1. 相邻的所有值都大于这个点的答案,显然这个点就是要求的点;

    2. 相邻的点只有一个的值,小于这个点统计出的答案,就直接向这棵更小的子树走,注意是走到“分治树”的下一个重心,继续操作。

      1 //It is made by Awson on 2018.1.9
      2 #include <set>
      3 #include <map>
      4 #include <cmath>
      5 #include <ctime>
      6 #include <queue>
      7 #include <stack>
      8 #include <cstdio>
      9 #include <string>
     10 #include <vector>
     11 #include <cstdlib>
     12 #include <cstring>
     13 #include <iostream>
     14 #include <algorithm>
     15 #define LL long long
     16 #define lowbit(x) ((x)&(-(x)))
     17 #define Max(a, b) ((a) > (b) ? (a) : (b))
     18 #define Min(a, b) ((a) < (b) ? (a) : (b))
     19 #define Swap(a, b) ((a) ^= (b), (b) ^= (a), (a) ^= (b))
     20 using namespace std;
     21 const int N = 1e5;
     22 const int INF = ~0u>>1;
     23 void read(int &x) {
     24     char ch; bool flag = 0;
     25     for (ch = getchar(); !isdigit(ch) && ((flag |= (ch == '-')) || 1); ch = getchar());
     26     for (x = 0; isdigit(ch); x = (x<<1)+(x<<3)+ch-48, ch = getchar());
     27     x *= 1-2*flag;
     28 }
     29 
     30 int n, q, u, v, c, fa[N+5], G;
     31 LL sum[N+5], dis1[N+5], dis2[N+5]; 
     32 struct tt {
     33     int to, next, cost;
     34 }G1edge[(N<<1)+5], G2edge[N+5];
     35 int G1path[N+5], G1top, G2path[N+5], G2top;
     36 void G1add(int u, int v, int c) {
     37     G1edge[++G1top].to = v, G1edge[G1top].cost = c, G1edge[G1top].next = G1path[u], G1path[u] = G1top;
     38 }
     39 void G2add(int u, int v, int c) {
     40     G2edge[++G2top].to = v, G2edge[G2top].cost = c, G2edge[G2top].next = G2path[u], G2path[u] = G2top;
     41 }
     42 namespace LCA {
     43     int lim, bin[30], dfn[N+5], tim, logn[(N<<1)+5];
     44     LL f[(N<<1)+5][25];
     45     void dfs(int o, LL cost, int father) {
     46     f[dfn[o] = ++tim][0] = cost;
     47     for (int i = G1path[o]; i; i = G1edge[i].next)
     48         if (G1edge[i].to != father) dfs(G1edge[i].to, cost+G1edge[i].cost, o), f[++tim][0] = cost;
     49     }
     50     LL query(int x, int y) {
     51     if (dfn[x] > dfn[y]) Swap(x, y);
     52     int lim = logn[dfn[y]-dfn[x]+1];
     53     return Min(f[dfn[x]][lim], f[dfn[y]-bin[lim]+1][lim]);
     54     }
     55     LL dist(int x, int y) {return f[dfn[x]][0]+f[dfn[y]][0]-(query(x, y)<<1); }
     56     void main() {
     57     lim = log(n<<1)/log(2); bin[0] = 1; for (int i = 1; i <= 25; i++) bin[i] = bin[i-1]<<1;
     58     logn[0] = -1; for (int i = 1; i <= (n<<1); i++) logn[i] = logn[i>>1]+1;
     59      dfs(1, 0, 0);
     60     for (int t = 1; t <= lim; t++) for (int i = 1; i+bin[t]-1 <= (n<<1); i++) f[i][t] = Min(f[i][t-1], f[i+bin[t-1]][t-1]);
     61     }
     62 }
     63 namespace Point_divide {
     64     int size[N+5], mx[N+5], vis[N+5], minsize, root;
     65     void get_size(int o, int fa) {
     66     size[o] = 1, mx[o] = 0;
     67     for (int i = G1path[o]; i; i = G1edge[i].next)
     68         if (G1edge[i].to != fa && !vis[G1edge[i].to]) {
     69         get_size(G1edge[i].to, o);
     70         size[o] += size[G1edge[i].to];
     71         if (size[G1edge[i].to] > mx[o]) mx[o] = size[G1edge[i].to];
     72         }
     73     }
     74     void get_root(int o, int pa, int fa) {
     75     mx[o] = Max(mx[o], size[pa]-size[o]);
     76     if (minsize > mx[o]) minsize = mx[o], root = o;
     77     for (int i = G1path[o]; i; i = G1edge[i].next)
     78         if (G1edge[i].to != fa && !vis[G1edge[i].to]) get_root(G1edge[i].to, pa, o);
     79     }
     80     void work(int o, int pa) {
     81     minsize = INF; get_size(o, 0), get_root(o, o, 0);
     82     vis[root] = 1; fa[root] = pa; int rt = root; G2add(pa, root, o);
     83     for (int i = G1path[root]; i; i = G1edge[i].next)
     84         if (!vis[G1edge[i].to]) work(G1edge[i].to, rt);
     85     G = rt;
     86     }
     87     void main() {work(1, 0); }
     88 }
     89 
     90 void update(int o, int c) {
     91     for (int x = o; x; x = fa[x]) {
     92     sum[x] += c;
     93     dis1[x] += (LL)c*LCA::dist(x, o);
     94     if (fa[x]) dis2[x] += (LL)c*LCA::dist(fa[x], o);
     95     }
     96 }
     97 LL get_ans(int o) {
     98     LL ans = 0;
     99     for (int x = o; x; x = fa[x]) {
    100     ans += dis1[x]+sum[x]*LCA::dist(x, o);
    101     if (fa[x]) ans -= sum[x]*LCA::dist(fa[x], o)+dis2[x];
    102     }
    103     return ans;
    104 }
    105 LL query(int o) {
    106     LL ans = get_ans(o);
    107     for (int i = G2path[o]; i; i = G2edge[i].next) {
    108     LL tmp = get_ans(G2edge[i].cost);
    109     if (tmp < ans) return query(G2edge[i].to);
    110     }
    111     return ans;
    112 }
    113 void work() {
    114     read(n), read(q);
    115     for (int i = 1; i < n; i++) read(u), read(v), read(c), G1add(u, v, c), G1add(v, u, c);
    116     LCA::main(); Point_divide::main();
    117     while (q--) {
    118     read(u), read(c); update(u, c);
    119     printf("%lld
    ", query(G));
    120     }
    121 }
    122 int main() {
    123     work();
    124     return 0;
    125 }
  • 相关阅读:
    codeblocks基本调试方法—gdb—Debugger
    五大开源Web服务器
    【u237】分数化小数
    【u230】回文词
    【t099】最接近神的人
    【t052】冰岛
    【t069】奇怪的迷宫
    【p092】分数线划定
    【u243】拓扑排序
    【u247】生物进化
  • 原文地址:https://www.cnblogs.com/NaVi-Awson/p/8251754.html
Copyright © 2011-2022 走看看