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 }
  • 相关阅读:
    MySQL-基本sql命令
    Java for LeetCode 203 Remove Linked List Elements
    Java for LeetCode 202 Happy Number
    Java for LeetCode 201 Bitwise AND of Numbers Range
    Java for LeetCode 200 Number of Islands
    Java for LeetCode 199 Binary Tree Right Side View
    Java for LeetCode 198 House Robber
    Java for LeetCode 191 Number of 1 Bits
    Java for LeetCode 190 Reverse Bits
    Java for LeetCode 189 Rotate Array
  • 原文地址:https://www.cnblogs.com/NaVi-Awson/p/8251754.html
Copyright © 2011-2022 走看看