bzoj4763
$分块$
$一个很有趣的技巧$
$在树上选sqrt(n)个关键点,每两个关键点之间的距离<=sqrt(n),每个关键点属于一条链$
$预处理出每两个关键点的bitset$
$每次询问就暴力向上爬,合并bitset$
$由于要查询,所以要手写bitset$
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> using namespace std; typedef unsigned long long ull; const int bl = 470, N = 1e5 + 5; ull Num[65537]; vector<int> G[N]; int n, m, f, bbl, last; ull Max; int fa[N][18], dep[N], mx[N], w[N], mark[N], top[N], mir[N]; int read() { int x = 0, f = 1; char c = getchar(); while(!isdigit(c)) { if(c == '-') { f = -1; } c = getchar(); } while(isdigit(c)) { x = x * 10 + c - '0'; c = getchar(); } return x * f; } struct Bitset { int len; ull s[bl]; void clear() { for(int i = 0; i <= len; ++i) { s[i] = 0; } len = 0; } void operator |= (const Bitset &a) { len = max(len, a.len); for(int i = 0; i <= len; ++i) { s[i] |= a.s[i]; } } void operator |= (int b) { len = max(len, b >> 6); s[b >> 6] |= 1LL << (b & 63); } int num() { int ret = 0; for(int i = 0; i <= len; ++i) { ret += Num[s[i] >> 48] + Num[(s[i] >> 32) & 65535] + Num[(s[i] >> 16) & 65535] + Num[s[i] & 65535]; } return ret; } int mex() { for(int i = 0; i <= len; ++i) { if(s[i] != Max) { for(int j = 0; j < 64; ++j) { if(!(s[i] & (1LL << j))) { return i * 64 + j; } } } } } } b[350][350], ans; void dfs(int u) { mx[u] = dep[u]; for(int i = 0; i < G[u].size(); ++i) { int v = G[u][i]; if(v == fa[u][0]) { continue; } fa[v][0] = u; dep[v] = dep[u] + 1; dfs(v); mx[u] = max(mx[u], mx[v]); } if(mx[u] - dep[u] >= bbl || u == 1) { mark[u] = ++mark[0]; mir[mark[u]] = u; mx[u] = 0; } } int lca(int u, int v) { if(dep[u] < dep[v]) { swap(u, v); } int d = dep[u] - dep[v]; for(int i = 0; i < 18; ++i) { if(d & (1 << i)) { u = fa[u][i]; } } if(u == v) { return u; } for(int i = 17; i >= 0; --i) { if(fa[u][i] != fa[v][i]) { u = fa[u][i]; v = fa[v][i]; } } return fa[u][0]; } int main() { n = read(); m = read(); f = read(); bbl = sqrt(n); for(int i = 0; i < 64; ++i) { Max |= 1LL << i; } for(int i = 0; i < 65536; ++i) { for(int j = 0; j < 16; ++j) { if(i & (1 << j)) { ++Num[i]; } } } for(int i = 1; i <= n; ++i) { w[i] = read(); } for(int i = 1; i < n; ++i) { int u = read(), v = read(); G[u].push_back(v); G[v].push_back(u); } dep[1] = 1; dfs(1); for(int j = 1; j <= 17; ++j) { for(int i = 1; i <= n; ++i) { fa[i][j] = fa[fa[i][j - 1]][j - 1]; } } for(int i = 1; i <= mark[0]; ++i) { ans.clear(); ans |= w[mir[i]]; int x; b[i][i] |= w[mir[i]]; for(x = fa[mir[i]][0]; x; x = fa[x][0]) { ans |= w[x]; if(mark[x]) { b[i][mark[x]] = ans; if(!top[mir[i]]) { top[mir[i]] = x; } } } } while(m--) { int a = read(), x, y, z; ans.clear(); while(a--) { x = read(); y = read(); if(f) { x = x ^ last; y = y ^ last; } ans |= w[x]; ans |= w[y]; z = lca(x, y); for(; x && !mark[x] && dep[x] > z; x = fa[x][0]) { ans |= w[x]; } for(; y && !mark[y] && dep[y] > z; y = fa[y][0]) { ans |= w[y]; } int xx, yy; for(xx = x; dep[top[xx]] >= dep[z]; xx = top[xx]); for(yy = y; dep[top[yy]] >= dep[z]; yy = top[yy]); ans |= b[mark[x]][mark[xx]]; ans |= b[mark[y]][mark[yy]]; for(x = xx; dep[x] >= dep[z]; x = fa[x][0]) { ans |= w[x]; } for(y = yy; dep[y] >= dep[z]; y = fa[y][0]) { ans |= w[y]; } } int ta = ans.num(), tb = ans.mex(); last = ta + tb; printf("%d %d\n", ta, tb); } return 0; }