BZOJ3052: [wc2013]糖果公园【树上带修莫队】

Description

img

Input

img

Output

img

Sample Input

img

Sample Input

Sample Output

84
131
27
84

HINT

img

img


思路

非常模板的树上带修莫队

真的很裸

直接暴力维护就可以了

注意一下询问的第二关键字是第二个节点所在块,第三关键字是时间,不然jmr说会出锅


#include<bits/stdc++.h>

using namespace std;

typedef long long ll;

const int N = 1e5 + 10;

int n, m, q, col[N], c[N];
int dfn[N], dfn_ind = 0;
int dep[N], fa[N][20];
int tot = 0, head[N];
ll v[N], w[N], nowans = 0;
int top = 0, st[N << 1], bel[N];
int siz_block = 2000, cnt_block = 0;
int num[N], vis[N];

struct Query {
  int u, v, id;
  ll ans;
} Q[N];

bool cmp1(const Query &a, const Query &b) {
  if (bel[a.u] != bel[b.u]) return bel[a.u] < bel[b.u];
  if (bel[a.v] != bel[b.v]) return bel[a.v] < bel[b.v];
  return a.id < b.id;
}

bool cmp2(const Query &a, const Query &b) {
  return a.id < b.id;
}

struct Modify {
  int pos, bef, aft, id;
} M[N << 1];

struct Edge {
  int v, nxt;
} E[N << 1];


void addedge(int u, int v) {
  E[++tot] = (Edge) {v, head[u]};
  head[u] = tot;
} 

int dfs(int u) {
  int siz = 0;
  dfn[u] = ++dfn_ind;
  for (int i = 1; i <= 18; i++)
    fa[u][i] = fa[fa[u][i - 1]][i - 1];
  for (int i = head[u]; i; i = E[i].nxt) {
    int v = E[i].v;
    if (v == fa[u][0]) continue;
    fa[v][0] = u;
    dep[v] = dep[u] + 1;
    siz += dfs(v);
    if (siz >= siz_block) {
      ++cnt_block;
      while (siz) {
        bel[st[top--]] = cnt_block;
        --siz;
      }
    }
  }
  st[++top] = u;
  return siz + 1;
}

int lca(int x, int y) {
  if (dep[x] < dep[y]) swap(x, y);
  int delta = dep[x] - dep[y];
  for (int i = 0; i <= 18; i++)
    if ((delta >> i) & 1) x = fa[x][i];
  if (x == y) return x;
  for (int i = 18; i >= 0; i--) {
    if (fa[x][i] != fa[y][i]) {
      x = fa[x][i];
      y = fa[y][i];
    }
  }
  return fa[x][0];
}

void reverse(int x) {
  if (vis[x]) {
    nowans -= w[num[col[x]]] * v[col[x]];
    num[col[x]]--;  
  } else {
    num[col[x]]++;
    nowans += w[num[col[x]]] * v[col[x]];
  }
  vis[x] ^= 1;
}

void solve(int x, int y) {
  while (x != y) {
    if (dep[x] > dep[y]) {
      reverse(x);
      x = fa[x][0];
    } else {
      reverse(y);
      y = fa[y][0];
    }
  }
}

int main() {
#ifdef dream_maker
  freopen("input.txt", "r", stdin);
#endif
  scanf("%d %d %d", &n, &m, &q);
  for (int i = 1; i <= m; i++) scanf("%lld", &v[i]);
  for (int i = 1; i <= n; i++) scanf("%lld", &w[i]);
  for (int i = 1; i < n; i++) {
    int u, v;
    scanf("%d %d", &u, &v);
    addedge(u, v);
    addedge(v, u);
  }
  for (int i = 1; i <= n; i++) {
    scanf("%d", &col[i]);
    c[i] = col[i];
  }
  int cntq = 0, cntm = 0;
  for (int i = 1; i <= q; i++) {
    int typ; scanf("%d", &typ);
    if (typ) {
      ++cntq;
      Q[cntq].id = i;
      scanf("%d %d", &Q[cntq].u, &Q[cntq].v);
    } else {
      ++cntm;
      M[cntm].id = i;
      int x, y;
      scanf("%d %d", &x, &y);
      M[cntm].pos = x;
      M[cntm].bef = c[x];
      c[x] = y;
      M[cntm].aft = c[x];
    }
  }
  dfs(1);
  ++cnt_block;
  while (top) {
    bel[st[top--]] = cnt_block;
  }
  sort(Q + 1, Q + cntq + 1, cmp1);
  int cur = 0;
  for (int i = 1; i <= cntq; i++) {
    while (cur < cntm && M[cur + 1].id <= Q[i].id) {
      ++cur;
      if (vis[M[cur].pos]) {
        nowans -= w[num[col[M[cur].pos]]] * v[col[M[cur].pos]];
        num[col[M[cur].pos]]--;
      }
      col[M[cur].pos] = M[cur].aft;
      if (vis[M[cur].pos]) {
        num[col[M[cur].pos]]++;
        nowans += w[num[col[M[cur].pos]]] * v[col[M[cur].pos]];
      } 
    }
    while (cur >= 1 && M[cur].id >= Q[i].id) {
      if (vis[M[cur].pos]) {
        nowans -= w[num[col[M[cur].pos]]] * v[col[M[cur].pos]];
        num[col[M[cur].pos]]--;
      }
      col[M[cur].pos] = M[cur].bef;
      if (vis[M[cur].pos]) {
        num[col[M[cur].pos]]++;
        nowans += w[num[col[M[cur].pos]]] * v[col[M[cur].pos]];
      } 
      --cur;
    }
    if (i == 1) {
      solve(Q[i].u, Q[i].v);
    } else {
      solve(Q[i].u, Q[i - 1].u);
      solve(Q[i].v, Q[i - 1].v);
    }
    int t = lca(Q[i].u, Q[i].v);
    reverse(t);
    Q[i].ans = nowans;
    reverse(t);
  }
  sort(Q + 1, Q + cntq + 1, cmp2);
  for (int i = 1; i <= cntq; i++) 
    printf("%lld\n", Q[i].ans);
  return 0;
}
posted @ 2018-12-29 14:16  Dream_maker_yk  阅读(248)  评论(0编辑  收藏  举报