[BZOJ4763][P3603]雪辉[手写bitset+静态分块]

题意:给一个n个点的树,点有点权,有m次询问,每次询问多条链的并有多少种不同的点权以及它的mex
mex就是一个集合中最小的没有出现的非负整数,注意0要算

rand出 \(\sqrt n\)个点,把每次查询拆成 x->fx0->fx->lca->fy->fy0->y

#include <bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
template<typename T> void read(T & x) {
  int c = getchar(); x = 0;
  while(!isdigit(c)) c = getchar();
  while(isdigit(c)) x = x * 10 + c - '0', c = getchar();
}
#define read2(a, b) (read(a), read(b))
#define read3(a, b, c) (read(a), read2(b, c))
const int MAXN = 100007;
struct Edge{
  int v, next;
}G[MAXN<<1]; int tot, head[MAXN], dq[MAXN], n, q, siz[MAXN], dep[MAXN], top[MAXN], anc[MAXN], son[MAXN], cnt[1<<16], s, m, u, v, up[MAXN], pos[357], lca, b, tpos[MAXN];
bool vis[MAXN], f;
int _popcount(int x) {
  static int ret;
  for(ret = 0; x; ret += x & 1, x >>= 1);
  return ret;
}
int popcount(ull x) {
  static int ret = 0;
  for(ret = 0; x; ret += cnt[x & 0xffff], x >>= 16);
  return ret;
}
inline void chmax(int &x, int y) {if (x < y) x = y;}
struct Bitset{
  static const ull ful = 0xffffffffffffffff;
  ull bit[470]; int len, Mex, Num;
  void reset() {for(int i = 0; i <= len; ++i) bit[i] = 0; len = 0; Num = Mex = 0;}
  void operator |= (const Bitset &rhs) {
    chmax(len, rhs.len);
    for(int i = 0; i <= len; ++i) bit[i] |= rhs.bit[i];
  }
  void operator |= (int x) {
    chmax(len, x >> 6);
    bit[x >> 6] |= 1ull << (x & 63);
  }
  int mex() {
    for(int i = 0; i <= len; ++i) 
      if (bit[i] != ful) 
        for(int j = 0; j < 64; ++j) if (!(bit[i] & (1ull<<j))) return Mex = i * 64 + j;
  }
  int num() {
    for(int i = 0; i <= len; ++i) 
      Num += popcount(bit[i]);
    return Num;
  }
}dis[353][351], t; 
  
void add(int u, int v) {G[++tot] = (Edge){v, head[u]}; head[u] = tot;}
#define v G[i].v
void dfs1(int u) {
  dep[u] = dep[anc[u]] + 1;
  siz[u] = 1;
  for(int i = head[u]; i; i = G[i].next) {
    if (v == anc[u]) continue;
    anc[v] = u;
    dfs1(v), siz[u] += siz[v];
    if (siz[son[u]] <= siz[v]) son[u] = v;
  }
}
void dfs2(int u, int t) {
  top[u] = t;
  if (son[u]) dfs2(son[u], t);
  for(int i = head[u]; i; i = G[i].next) 
    if (v != son[u] && v != anc[u]) dfs2(v, v);
}
#undef v
int LCA(int u, int v) {
  while(top[u] != top[v]) 
    dep[top[u]] >= dep[top[v]] ? u = anc[top[u]] : v = anc[top[v]];
  return dep[u] < dep[v] ? u : v;
}
#define u1(x) while(!vis[x] && x != lca) t |= dq[x], x = anc[x];
#define u3(x) while(x != lca) t |= dq[x], x = anc[x];
void u2(int &x) {
  int nx = x;
  while(dep[up[x]] > dep[lca]) x = up[x];
  t |= dis[tpos[nx]][tpos[x]];
}
void update() {
  u1(u); u1(v);
  u2(u); u2(v);
  u3(u); u3(v);
}
int main(void) {
//  freopen("data.in", "r", stdin);
  for(int i = 0; i < (1<<16); ++i) cnt[i] = _popcount(i);
  read3(n, m, f);
  for(int i = 1; i <= n; ++i) read(dq[i]);
  for(int i = 1; i < n; ++i) read2(u, v), add(u, v), add(v, u);
  dfs1(1);
  dfs2(1, 1);
  s = sqrt(n);
  for(int i = 1; i <= s; ++i) {
    do q = rand()%n+1;while(vis[q]);
    vis[q] = 1, tpos[pos[i] = q] = i;
  }
  for(int i = 1; i <= s; ++i) {
    int u = pos[i]; t.reset();
    while(u){
      t |= dq[u];
      if (vis[u] && u != pos[i]) {
        dis[i][tpos[u]] |= t;
        if (!up[pos[i]]) up[pos[i]] = u;
      }
      u = anc[u];
    }
  }
  int last = 0;
  while(m--) {
    t.reset(); read(b);
    while(b--) {
      read2(u, v); 
      if (f) u ^= last, v ^= last;
      lca = LCA(u, v), t |= dq[lca];
      update();
    }
    last = t.num()+t.mex();
    printf("%d %d\n", t.Num, t.Mex);
  }
  return 0;
}
posted @ 2018-12-28 16:20  QvvQ  阅读(196)  评论(0编辑  收藏  举报