【BZOJ】3730: 震波
题解
查询距离一个点距离在一定范围内的点,直接点分树,前缀和用树状数组维护
答案是当前重心距离不超过k - (x到重心距离)的点的前缀和,减去在x所在子树中,距离重心不超过k - (x到重心距离)的前缀和
代码
#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int,int>
#define mp make_pair
#define pb push_back
#define space putchar(' ')
#define enter putchar('\n')
#define eps 1e-10
#define MAXN 100005
//#define ivorysi
using namespace std;
typedef long long int64;
typedef unsigned int u32;
typedef double db;
template<class T>
void read(T &res) {
res = 0;T f = 1;char c = getchar();
while(c < '0' || c > '9') {
if(c == '-') f = -1;
c = getchar();
}
while(c >= '0' && c <= '9') {
res = res * 10 +c - '0';
c = getchar();
}
res *= f;
}
template<class T>
void out(T x) {
if(x < 0) {x = -x;putchar('-');}
if(x >= 10) {
out(x / 10);
}
putchar('0' + x % 10);
}
int lowbit(int x) {
return x & (-x);
}
struct BIT {
vector<int64> v;
void init(int n) {
for(int i = 1 ; i <= n + 1 ; ++i) v.pb(0);
}
void Insert(int x,int64 p) {
while(x < v.size()) {
v[x] += p;
x += lowbit(x);
}
}
int64 Query(int x) {
int64 res = 0;
x = min(x,(int)v.size() - 1);
while(x > 0) {
res += v[x];
x -= lowbit(x);
}
return res;
}
};
struct node {
int to,next;
}E[MAXN * 2];
struct pdt {
BIT rt,pre;
vector<int> aux,sub,dep;
}tr[MAXN];
int head[MAXN],sumE;
int N,M,d[MAXN];
int64 val[MAXN];
bool vis[MAXN];
vector<int> poi;
void add(int u,int v) {
E[++sumE].to = v;
E[sumE].next = head[u];
head[u] = sumE;
}
int Calc_G(int st) {
static int fa[MAXN],siz[MAXN],son[MAXN],que[MAXN],ql,qr;
ql = 1,qr = 0;
que[++qr] = st;
fa[st] = 0;siz[st] = 1;son[st] = 0;
while(ql <= qr) {
int u = que[ql++];
for(int i = head[u] ; i ; i = E[i].next) {
int v = E[i].to;
if(v != fa[u] && !vis[v]) {
fa[v] = u;siz[v] = 1;son[v] = 0;que[++qr] = v;
}
}
}
int res = que[qr];
for(int i = qr ; i >= 1 ; --i) {
int u = que[i];
if(fa[u]) {
siz[fa[u]] += siz[u];
son[fa[u]] = max(son[fa[u]],siz[u]);
}
son[u] = max(son[u],qr - siz[u]);
if(son[u] < son[res]) res = u;
}
return res;
}
int get_max_dep(int u,int fa) {
d[u] = d[fa] + 1;
int res = d[u];
poi.pb(u);
for(int i = head[u] ; i ; i = E[i].next) {
int v = E[i].to;
if(!vis[v] && v != fa) {
res = max(res,get_max_dep(v,u));
}
}
return res;
}
void dfs_divide(int u) {
int G = Calc_G(u);
vis[G] = 1;
d[G] = 1;
poi.clear();
tr[G].rt.init(get_max_dep(G,0));
for(int i = 0 ; i < poi.size() ; ++i) {
tr[G].rt.Insert(d[poi[i]],val[poi[i]]);
tr[poi[i]].aux.pb(G);
tr[poi[i]].dep.pb(d[poi[i]]);
}
for(int i = head[G] ; i ; i = E[i].next) {
int v = E[i].to;
if(!vis[v]) {
int s = Calc_G(v);
poi.clear();
tr[s].pre.init(get_max_dep(v,G));
for(int j = 0 ; j < poi.size() ; ++j) {
tr[poi[j]].sub.pb(s);
tr[s].pre.Insert(d[poi[j]],val[poi[j]]);
}
}
}
for(int i = head[G] ; i ; i = E[i].next) {
int v = E[i].to;
if(!vis[v]) dfs_divide(v);
}
}
void Init() {
read(N);read(M);
int u,v;
for(int i = 1 ; i <= N ; ++i) read(val[i]);
for(int i = 1 ; i < N ; ++i) {
read(u);read(v);
add(u,v);add(v,u);
}
dfs_divide(1);
}
int64 Calc(int x,int k) {
int64 res = 0;
for(int i = tr[x].aux.size() - 1 ; i >= 0 ; --i) {
int u = tr[x].aux[i];
res += tr[u].rt.Query(k + 2 - tr[x].dep[i]);
}
for(int i = tr[x].sub.size() - 1 ; i >= 0 ; --i) {
int u = tr[x].sub[i];
res -= tr[u].pre.Query(k + 2 - tr[x].dep[i]);
}
return res;
}
void Change(int x,int y) {
for(int i = tr[x].aux.size() - 1 ; i >= 0 ; --i) {
int u = tr[x].aux[i];
tr[u].rt.Insert(tr[x].dep[i],-val[x]);
tr[u].rt.Insert(tr[x].dep[i],y);
}
for(int i = tr[x].sub.size() - 1 ; i >= 0 ; --i) {
int u = tr[x].sub[i];
tr[u].pre.Insert(tr[x].dep[i],-val[x]);
tr[u].pre.Insert(tr[x].dep[i],y);
}
val[x] = y;
}
void Solve() {
int la = 0;
int x,op,y;
for(int i = 1 ; i <= M ; ++i) {
read(op);read(x);read(y);
x = x ^ la;y = y ^ la;
if(op == 0) {
la = Calc(x,y);
out(la);enter;
}
else {
Change(x,y);
}
}
}
int main() {
#ifdef ivorysi
freopen("f1.in","r",stdin);
#endif
Init();
Solve();
}