1. 程式人生 > >BZOJ4012: [HNOI2015]開店【動態點分治】

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\n", 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\n", lastans);
  }
  return 0;
}