zoukankan      html  css  js  c++  java
  • BZOJ4012: [HNOI2015]开店【动态点分治】

    Description

    风见幽香有一个好朋友叫八云紫,她们经常一起看星星看月亮从诗词歌赋谈到

    人生哲学。最近她们灵机一动,打算在幻想乡开一家小店来做生意赚点钱。这样的

    想法当然非常好啦,但是她们也发现她们面临着一个问题,那就是店开在哪里,面

    向什么样的人群。很神奇的是,幻想乡的地图是一个树形结构,幻想乡一共有 n

    个地方,编号为 1 到 n,被 n-1 条带权的边连接起来。每个地方都住着一个妖怪,

    其中第 i 个地方的妖怪年龄是 (x_i)。妖怪都是些比较喜欢安静的家伙,所以它们并

    不希望和很多妖怪相邻。所以这个树所有顶点的度数都小于或等于 3。妖怪和人一

    样,兴趣点随着年龄的变化自然就会变化,比如我们的 18 岁少女幽香和八云紫就

    比较喜欢可爱的东西。幽香通过研究发现,基本上妖怪的兴趣只跟年龄有关,所以

    幽香打算选择一个地方 u(u为编号),然后在 u开一家面向年龄在 L到R 之间(即

    年龄大于等于 L、小于等于 R)的妖怪的店。也有可能 u这个地方离这些妖怪比较

    远,于是幽香就想要知道所有年龄在 L 到 R 之间的妖怪,到点 u 的距离的和是多

    少(妖怪到 u 的距离是该妖怪所在地方到 u 的路径上的边的权之和) ,幽香把这个

    称为这个开店方案的方便值。幽香她们还没有决定要把店开在哪里,八云紫倒是准

    备了很多方案,于是幽香想要知道,对于每个方案,方便值是多少呢。

    Input

    第一行三个用空格分开的数 n、Q和A,表示树的大小、开店的方案个数和妖

    怪的年龄上限。

    第二行n个用空格分开的数 (x_1、x_2、…、x_n,x_i) 表示第i 个地点妖怪的年

    龄,满足0<=(x_i)<A。(年龄是可以为 0的,例如刚出生的妖怪的年龄为 0。)

    接下来 n-1 行,每行三个用空格分开的数 a、b、c,表示树上的顶点 a 和 b 之

    间有一条权为c(1 <= c <= 1000)的边,a和b 是顶点编号。

    接下来Q行,每行三个用空格分开的数 u、 a、 b。对于这 Q行的每一行,用 a、

    b、A计算出 L和R,表示询问“在地方 u开店,面向妖怪的年龄区间为[L,R]的方

    案的方便值是多少”。对于其中第 1 行,L 和 R 的计算方法为:L=min(a%A,b%A),

    R=max(a%A,b%A)。对于第 2到第 Q行,假设前一行得到的方便值为 ans,那么当

    前行的 L 和 R 计算方法为: L=min((a+ans)%A,(b+ans)%A),

    R=max((a+ans)%A,(b+ans)%A)。

    Output

    对于每个方案,输出一行表示方便值。

    Sample Input

    10 10 10
    0 0 7 2 1 4 7 7 7 9
    1 2 270
    2 3 217
    1 4 326
    2 5 361
    4 6 116
    3 7 38
    1 8 800
    6 9 210
    7 10 278
    8 9 8
    2 8 0
    9 3 1
    8 0 8
    4 2 7
    9 7 3
    4 7 0
    2 2 7
    3 2 1
    2 3 4

    Sample Output

    1603
    957
    7161
    9466
    3232
    5223
    1879
    1669
    1282
    0

    HINT

    满足 n<=150000,Q<=200000。对于所有数据,满足 A<=10^9


    思路

    很显然可以用动态点分治做

    一开始想到要维护size和sumdistans就果断线段树了

    然后就又MLE又RE

    后来发现信息是静态的,没有修改我怎么才发现

    然后就可以直接上vector大法+二分了

    还不用离散化真好。。。。


    线段树:

    #include<bits/stdc++.h>
     
    using namespace std;
     
    int read() {
      int res = 0, w = 1; char c = getchar();
      while (!isdigit(c) && c != '-') c = getchar();
      if (c == '-') w = -1, c = getchar();
      while (isdigit(c)) res = (res << 1) + (res << 3) + c - '0', c = getchar();
      return res * w;
    }
     
    typedef long long ll;
    typedef pair<ll, int> pi;
    const int N = 2e5 + 10;
    const int LOG = 40;
     
    struct Edge {
      int v, w, nxt;
      Edge(int v = 0, int w = 0, int nxt = 0): v(v), w(w), nxt(nxt) {}
    } E[N << 1];
    int head[N], tot = 0;
    int n, q, A, num_age, age[N], pre[N];
    char c[10];
     
    void addedge(int u, int v, int w) {
      E[++tot] = Edge(v, w, head[u]);
      head[u] = tot;
    }
     
    namespace LCA {
     
    struct Node {
      int id, depth;
      Node(int id = 0, int depth = 0): id(id), depth(depth) {}
      bool operator < (const Node b) const {
        return depth < b.depth;
      }
    } ST[N << 1][LOG];
    int first[N], dep[N], log[N << 1], dist[N], len;
     
    void dfs(int u, int fa) {
      ST[++len][0] = Node(u, dep[u]);
      first[u] = len;
      for (int i = head[u]; i; i = E[i].nxt) {
        int v = E[i].v;
        if (v == fa) continue;
        dep[v] = dep[u] + 1;
        dist[v] = dist[u] + E[i].w;
        dfs(v, u);
        ST[++len][0] = Node(u, dep[u]);
      }
    }
     
    void init() {
      dfs(1, 0);
      log[1] = 0;
      for (int i = 2; i <= len; i++) log[i] = log[i >> 1] + 1;
      for (int j = 1; (1 << j) <= len; j++) {
        for (int i = 1; i + (1 << j) - 1 <= len; i++) {
          ST[i][j] = min(ST[i][j - 1], ST[i + (1 << (j - 1))][j - 1]);
        }
      }
    }
     
    int getdis(int u, int v) {
      if (first[u] < first[v]) swap(u, v);
      int k = log[first[u] - first[v] + 1];
      int lca = min(ST[first[v]][k], ST[first[u] - (1 << k) + 1][k]).id;
      return dist[u] + dist[v] - (dist[lca] << 1);
    }
     
    }
     
    namespace Segment_Tree {
       
    int tot = 0, rt[N << 1], ls[(N * LOG) << 1], rs[(N * LOG) << 1];
    ll val[(N * LOG) << 1], siz[(N * LOG) << 1];
     
    void modify(int &t, int l, int r, int pos, int vl) {
      if (!t) t =++tot;
      val[t] += vl, siz[t]++;
      if (l == r) return;
      int mid = (l + r) >> 1;
      if (pos <= mid) modify(ls[t], l, mid, pos, vl);
      else modify(rs[t], mid + 1, r, pos, vl);
    }
     
    pi query(int t, int l, int r, int ql, int qr) {
      if (!t) return pi(0ll, 0);
      if (ql <= l && r <= qr) return pi(val[t], siz[t]);
      int mid = (l + r) >> 1;
      if (qr <= mid) return query(ls[t], l, mid, ql, qr);
      else if (ql > mid) return query(rs[t], mid + 1, r, ql, qr);
      else {
        pi ansl = query(ls[t], l, mid, ql, mid);
        pi ansr = query(rs[t], mid + 1, r, mid + 1, qr);  
        return  pi(ansl.first + ansr.first, ansl.second + ansr.second);
      }
    }
     
    }
     
    namespace Tree_Devide {
       
    int father[N], siz[N], F[N], siz_all, root;
    bool vis[N]; 
     
    void getsiz(int u, int fa) {
      siz[u] = 1;
      for (int i = head[u]; i; i = E[i].nxt) {
        int v = E[i].v;
        if (v == fa || vis[v]) continue;
        getsiz(v, u);
        siz[u] += siz[v];
      }
    }
     
    void getroot(int u, int fa) {
      F[u] = 0;
      for (int i = head[u]; i; i = E[i].nxt) {
        int v = E[i].v;
        if (v == fa || vis[v]) continue;
        getroot(v, u);
        F[u] = max(F[u], siz[v]);
      }
      F[u] = max(F[u], siz_all - siz[u]);
      if (F[u] < F[root]) root = u;
    }
     
    void solve(int u, int fa) {
      father[u] = fa;
      vis[u] = 1;
      getsiz(u, 0);
      for (int i = head[u]; i; i = E[i].nxt) {
        int v = E[i].v;
        if (vis[v]) continue;
        F[root = 0] = siz_all = siz[v];
        getroot(v, 0);
        solve(root, u);
      }
    }
     
    void init() {
      getsiz(1, 0);
      F[root = 0] = siz_all = n;
      getroot(1, 0);
      solve(root, 0);
    }
     
    #define ID0(p) (p)
    #define ID1(p) (p + n) 
     
    void modify_tree(int u) {
      using namespace Segment_Tree;
      modify(rt[ID0(u)], 1, num_age, age[u], 0);
      for (int cur = u; father[cur]; cur = father[cur]) {
        int dis = LCA::getdis(u, father[cur]);
        modify(rt[ID0(father[cur])], 1, num_age, age[u], dis);
        modify(rt[ID1(cur)], 1, num_age, age[u], dis);
      }
    }
     
    ll query_tree(int u, int l, int r) {
      using namespace Segment_Tree;
      ll res = query(rt[ID0(u)], 1, num_age, l, r).first;
      pi now;
      for (int cur = u; father[cur]; cur = father[cur]) {
        int dis = LCA::getdis(u, father[cur]);
        now = query(rt[ID0(father[cur])], 1, num_age, l, r);
        res += now.first + 1ll * dis * now.second;
        now = query(rt[ID1(cur)], 1, num_age, l, r);
        res -= now.first + 1ll * dis * now.second;
      }
      return res;
    }
     
    }
     
    int main() {
    #ifdef dream_maker
      freopen("input.txt", "r", stdin);
    #endif
      n = read(), q = read(), A = read();
      for (int i = 1; i <= n; i++) {
        pre[i] = age[i] = read(); 
      }
      sort(pre + 1, pre + n + 1);
      num_age = unique(pre + 1, pre + n + 1) - pre - 1;
      for (int i = 1; i <= n; i++) {
        age[i] = lower_bound(pre + 1, pre + num_age + 1, age[i]) - pre;
      }
      for (int i = 1; i < n; i++) {
        int u = read(), v = read(), w = read();
        addedge(u, v, w);
        addedge(v, u, w);
      }
      LCA::init();
      Tree_Devide::init();
      for (int i = 1; i <= n; i++) {
        Tree_Devide::modify_tree(i);
      }
      ll lastans = 0;
      while (q--) {
        int u = read(), l = (read() % A + lastans % A) % A, r = (read() % A + lastans % A) % A;
        if (l > r) swap(l, r);
        l = lower_bound(pre + 1, pre + num_age + 1, l) - pre;
        r = upper_bound(pre + 1, pre + num_age + 1, r) - pre - 1;
        lastans = Tree_Devide::query_tree(u, l, r);
        printf("%lld
    ", lastans);
      }
      return 0;
    }
    

    vector+二分

    #include<bits/stdc++.h>
    
    using namespace std;
    
    int read() {
      int res = 0, w = 1; char c = getchar();
      while (!isdigit(c) && c != '-') c = getchar();
      if (c == '-') w = -1, c = getchar();
      while (isdigit(c)) res = (res << 1) + (res << 3) + c - '0', c = getchar();
      return res * w;
    }
    
    typedef long long ll;
    typedef pair<int, ll> pi;
    const int INF_of_int = 1e9;
    const int N = 2e5 + 10;
    const int LOG = 40;
    
    struct Edge {
      int v, w, nxt;
      Edge(int v = 0, int w = 0, int nxt = 0): v(v), w(w), nxt(nxt) {}
    } E[N << 1];
    int head[N], tot = 0;
    int n, q, A, age[N];
    
    void addedge(int u, int v, int w) {
      E[++tot] = Edge(v, w, head[u]);
      head[u] = tot;
    }
    
    namespace LCA {
    
    struct Node {
      int id, depth;
      Node(int id = 0, int depth = 0): id(id), depth(depth) {}
      bool operator < (const Node b) const {
        return depth < b.depth;
      }
    } ST[N << 1][LOG];
    int first[N], dep[N], log[N << 1], dist[N], len;
    
    void dfs(int u, int fa) {
      ST[++len][0] = Node(u, dep[u]);
      first[u] = len;
      for (int i = head[u]; i; i = E[i].nxt) {
        int v = E[i].v;
        if (v == fa) continue;
        dep[v] = dep[u] + 1;
        dist[v] = dist[u] + E[i].w;
        dfs(v, u);
        ST[++len][0] = Node(u, dep[u]);
      }
    }
    
    void init() {
      dfs(1, 0);
      log[1] = 0;
      for (int i = 2; i <= len; i++) log[i] = log[i >> 1] + 1;
      for (int j = 1; (1 << j) <= len; j++) {
        for (int i = 1; i + (1 << j) - 1 <= len; i++) {
          ST[i][j] = min(ST[i][j - 1], ST[i + (1 << (j - 1))][j - 1]);
        }
      }
    }
    
    int getdis(int u, int v) {
      if (first[u] < first[v]) swap(u, v);
      int k = log[first[u] - first[v] + 1];
      int lca = min(ST[first[v]][k], ST[first[u] - (1 << k) + 1][k]).id;
      return dist[u] + dist[v] - (dist[lca] << 1);
    }
    
    }
    
    namespace Tree_Devide {
    
    int father[N], siz[N], F[N], siz_all, root;
    bool vis[N]; 
    vector<pi> sum[2][N];
    
    void getsiz(int u, int fa) {
      siz[u] = 1;
      sum[0][root].push_back(pi(age[u], LCA::getdis(u, root)));
      sum[1][root].push_back(pi(age[u], LCA::getdis(u, father[root])));
      for (int i = head[u]; i; i = E[i].nxt) {
        int v = E[i].v;
        if (v == fa || vis[v]) continue;
        getsiz(v, u);
        siz[u] += siz[v];
      }
    }
    
    void getroot(int u, int fa) {
      F[u] = 0;
      for (int i = head[u]; i; i = E[i].nxt) {
        int v = E[i].v;
        if (v == fa || vis[v]) continue;
        getroot(v, u);
        F[u] = max(F[u], siz[v]);
      }
      F[u] = max(F[u], siz_all - siz[u]);
      if (F[u] < F[root]) root = u;
    }
    
    void solve(int u, int fa) {
      father[u] = fa;
      vis[u] = 1;
      sum[0][u].push_back(pi(-INF_of_int, 0));
      sum[1][u].push_back(pi(-INF_of_int, 0));
      getsiz(u, 0);
      sum[0][u].push_back(pi(INF_of_int + 1, 0));
      sum[1][u].push_back(pi(INF_of_int + 1, 0));
      sort(sum[0][u].begin(), sum[0][u].end());
      sort(sum[1][u].begin(), sum[1][u].end());
      int len;
      len = sum[0][u].size();
      for (int i = 1; i < len; i++) sum[0][u][i].second += sum[0][u][i - 1].second;
      len = sum[1][u].size();
      for (int i = 1; i < len; i++) sum[1][u][i].second += sum[1][u][i - 1].second;
      for (int i = head[u]; i; i = E[i].nxt) {
        int v = E[i].v;
        if (vis[v]) continue;
        F[root = 0] = siz_all = siz[v];
        getroot(v, 0);
        solve(root, u);
      }
    }
    
    void init() {
      getsiz(1, 0);
      F[root = 0] = siz_all = n;
      getroot(1, 0);
      solve(root, 0);
    }
    
    pi query(int u, int typ, int vl) {
      int l = 1, r = sum[typ][u].size() - 1, res = 0;
      while (l <= r) {
        int mid = (l + r) >> 1;
        if (sum[typ][u][mid].first <= vl) res = mid, l = mid + 1;
        else r = mid - 1;
      }
      return pi(res, sum[typ][u][res].second);
    }
    
    pi query(int u, int typ, int l, int r) {
      pi ansl = query(u, typ, l - 1);
      pi ansr = query(u, typ, r);
      return pi(ansr.first - ansl.first, ansr.second - ansl.second);
    }
    
    ll query_tree(int u, int l, int r) {
      ll res = query(u, 0, l, r).second;
      pi now;
      for (int cur = u; father[cur]; cur = father[cur]) {
        int dis = LCA::getdis(u, father[cur]);
        now = query(father[cur], 0, l, r);
        res += now.second + 1ll * dis * now.first;
        now = query(cur, 1, l, r);
        res -= now.second + 1ll * dis * now.first;
      }
      return res;
    }
    
    }
    
    int main() {
    #ifdef dream_maker
      freopen("input.txt", "r", stdin);
    #endif
      n = read(), q = read(), A = read();
      for (int i = 1; i <= n; i++) age[i] = read();
      for (int i = 1; i < n; i++) {
        int u = read(), v = read(), w = read();
        addedge(u, v, w);
        addedge(v, u, w);
      }
      LCA::init();
      Tree_Devide::init();
      ll lastans = 0;
      while (q--) {
        int u = read(), l = (read() % A + lastans % A) % A, r = (read() % A + lastans % A) % A;
        if (l > r) swap(l, r);
        lastans = Tree_Devide::query_tree(u, l, r);
        printf("%lld
    ", lastans);
      }
      return 0;
    }
    
  • 相关阅读:
    老调重弹--面向对象设计原则--S.O.L.I.D设计原则
    老调重弹--面向对象设计原则--GRASP设计原则
    【C#版本详情回顾】C#4.0主要功能列表
    【C#版本详情回顾】C#3.0主要功能列表
    【C#版本详情回顾】C#2.0主要功能列表
    .NET Framework和C#版本历史概览
    springmvc RESTful
    springmvc之json交互
    springmvc上传图片
    springmvc异常处理
  • 原文地址:https://www.cnblogs.com/dream-maker-yk/p/10054160.html
Copyright © 2011-2022 走看看