树链剖分总结
树链剖分:
已知一棵包含N个结点的树,每个节点具有点权:
操作1: 格式: 1 x y z 表示将树从x到y结点最短路径上所有节点的值都加上z
操作2: 格式: 2 x y 表示求树从x到y结点最短路径上所有节点的值之和
操作3: 格式: 3 x z 表示将以x为根节点的子树内所有节点值都加上z
操作4: 格式: 4 x 表示求以x为根节点的子树内所有节点值之和
(操作3,4可以用“dfs序 + 线段树”。)
即涉及两点间路径,子树内的点权的题。
与lca相比,多了修改操作。
复杂度:单次修改和查询均为O(logn*logn)
序列:query(x,y)
子树:tquery(dfn[x],dfn[x] + sz[x] - 1)
const ll maxn = 1e5 + 10;
ll n,m,r,p,k,idx;
ll a[maxn],head[maxn],dfn[maxn],top[maxn],d[maxn],f[maxn],sz[maxn],son[maxn],pos[maxn];
struct edge{
ll v,nxt;
}e[maxn << 1];
void adde(ll u,ll v){
e[k].v = v;
e[k].nxt = head[u];
head[u] = k++;
}
struct segment_tree{//based on dfn
ll sum,lzy;
}t[maxn << 2];
void pushup(ll u){
t[u].sum = t[u << 1].sum + t[u << 1 | 1].sum;
}
void pushdown(ll u,ll m){
if(t[u].lzy){
t[u << 1].lzy += t[u].lzy;
t[u << 1 | 1].lzy += t[u].lzy;
t[u << 1].sum += t[u].lzy * (m - (m >> 1));
t[u << 1 | 1].sum += t[u].lzy * (m >> 1);
t[u].lzy = 0;
}
}
void dfs1(ll u,ll fa){
d[u] = d[fa] + 1;f[u] = fa;
sz[u] = 1;//!!
for(ll i = head[u]; i != -1; i = e[i].nxt){
ll v = e[i].v;
if(v != fa){
dfs1(v,u);
sz[u] += sz[v];
if(sz[son[u]] < sz[v]) son[u] = v;
}
}
}
void dfs2(ll u,ll tp){
dfn[u] = ++idx;pos[idx] = u;top[u] = tp;
if(son[u]) dfs2(son[u],tp);
for(ll i = head[u]; i != -1; i = e[i].nxt){
ll v = e[i].v;
if(v != f[u] && v != son[u]){
dfs2(v,v);
}
}
}
void tbuild(ll u,ll l,ll r){
t[u].lzy = 0;
if(l == r) {
t[u].sum = a[pos[l]];//!!
return;
}
ll mid = (l + r) >> 1;
tbuild(lson);tbuild(rson);
pushup(u);
}
void tupdate(ll u,ll l,ll r,ll a,ll b,ll c){
if(a <= l && r <= b){
t[u].sum += (r - l + 1) * c;
t[u].lzy += c;
return;
}
ll mid = (l + r) >> 1;
pushdown(u,r - l + 1);
if(a <= mid) tupdate(lson,a,b,c);
if(mid < b) tupdate(rson,a,b,c);
pushup(u);
}
ll tquery(ll u,ll l,ll r,ll a,ll b){
if(a <= l && r <= b) return t[u].sum;
ll mid = (l + r) >> 1,ret = 0;
pushdown(u,r - l + 1);
if(a <= mid) ret += tquery(lson,a,b);
if(mid < b) ret += tquery(rson,a,b);
return ret;
}
void update(ll x,ll y,ll w){
while(top[x] != top[y]){
if(d[top[x]] < d[top[y]]) swap(x,y);
tupdate(1,1,n,dfn[top[x]],dfn[x],w);
x = f[top[x]];
}
if(d[x] < d[y]) swap(x,y);
tupdate(1,1,n,dfn[y],dfn[x],w);
}
ll query(ll x,ll y){
ll ret = 0;
while(top[x] != top[y]){
if(d[top[x]] < d[top[y]]) swap(x,y);
ret += tquery(1,1,n,dfn[top[x]],dfn[x]);
x = f[top[x]];
}
if(d[x] < d[y]) swap(x,y);
ret += tquery(1,1,n,dfn[y],dfn[x]);
return ret;
}
ll x,y,z,op;
int main(){
// freopen("a.txt","r",stdin);
memset(head,-1,sizeof(head));
n = read();m = read();r = read();p = read();
for(ll i = 1; i <= n; ++i) a[i] = read();
for(ll i = 1; i < n; ++i){
x = read();y = read();
adde(x,y);adde(y,x);
}
dfs1(r,0);dfs2(r,r);tbuild(1,1,n);
while(m--){
op = read();
if(op == 1){
x = read();y = read();z = read();
update(x,y,z);
}
else if(op == 2){
x = read();y = read();
printf("%lld\n",query(x,y));
}
else if(op == 3){
x = read();z = read();
tupdate(1,1,n,dfn[x],dfn[x] + sz[x] - 1,z);
}
else {
x = read();
printf("%lld\n",tquery(1,1,n,dfn[x],dfn[x] + sz[x] - 1));
}
}
return 0;
}
HYSBZ 3626 LCA
给出一个n个节点的有根树(编号为0到n-1,根节点为0)。一个点的深度定义为这个节点到根的距离+1。
设dep[i]表示点i的深度,LCA(i,j)表示i与j的最近公共祖先。
有q次询问,每次询问给出l r z,求 ∑ i l < = i < = r d e p [ L C A ( i , z ) ] \sum_i^{l<=i<=r}dep[LCA(i,z)] ∑il<=i<=rdep[LCA(i,z)]。
(即,求在[l,r]区间内的每个节点i与z的最近公共祖先的深度之和)
lca(x,y)的深度=x到根的每条边由0变成1后,y到根的边权和。差分一下,树剖即可。
注意:此题是0到n - 1
const ll maxn = 1e5 + 10;
const ll p = 201314;
ll n,m,k,idx;
ll head[maxn],dfn[maxn],top[maxn],d[maxn],f[maxn],sz[maxn],son[maxn],pos[maxn];
struct edge{
ll v,nxt;
}e[maxn << 1];
void adde(ll u,ll v){
e[k].v = v;
e[k].nxt = head[u];
head[u] = k++;
}
struct segment_tree{//based on dfn
ll sum,lzy;
}t[maxn << 2];
void pushup(ll u){
t[u].sum = t[u << 1].sum + t[u << 1 | 1].sum;
t[u].sum %= p;
}
void pushdown(ll u,ll m){
if(t[u].lzy){
t[u << 1].lzy += t[u].lzy;
t[u << 1 | 1].lzy += t[u].lzy;
t[u << 1].sum += t[u].lzy * (m - (m >> 1));
t[u << 1].sum %= p;
t[u << 1 | 1].sum += t[u].lzy * (m >> 1);
t[u << 1 | 1].sum %= p;
t[u].lzy = 0;
}
}
void dfs1(ll u,ll fa){
d[u] = d[fa] + 1;f[u] = fa;sz[u] = 1;//!!
for(ll i = head[u]; i != -1; i = e[i].nxt){
ll v = e[i].v;
if(v != fa){
dfs1(v,u);
sz[u] += sz[v];
if(sz[son[u]] < sz[v]) son[u] = v;
}
}
}
void dfs2(ll u,ll tp){
dfn[u] = ++idx;pos[idx] = u;top[u] = tp;
if(son[u]) dfs2(son[u],tp);
for(ll i = head[u]; i != -1; i = e[i].nxt){
ll v = e[i].v;
if(v != f[u] && v != son[u]){
dfs2(v,v);
}
}
}
void tbuild(ll u,ll l,ll r){
t[u].lzy = 0;
if(l == r) {
t[u].sum = 0;
return;
}
ll mid = (l + r) >> 1;
tbuild(lson);tbuild(rson);
pushup(u);
}
void tupdate(ll u,ll l,ll r,ll a,ll b,ll c){
if(a <= l && r <= b){
t[u].sum += (r - l + 1) * c;
t[u].sum %= p;
t[u].lzy += c;
return;
}
ll mid = (l + r) >> 1;
pushdown(u,r - l + 1);
if(a <= mid) tupdate(lson,a,b,c);
if(mid < b) tupdate(rson,a,b,c);
pushup(u);
}
ll tquery(ll u,ll l,ll r,ll a,ll b){
if(a <= l && r <= b) return t[u].sum;
ll mid = (l + r) >> 1,ret = 0;
pushdown(u,r - l + 1);
if(a <= mid) ret += tquery(lson,a,b);
if(mid < b) ret += tquery(rson,a,b);
return ret % p;
}
void update(ll x,ll y,ll w){
while(top[x] != top[y]){
if(d[top[x]] < d[top[y]]) swap(x,y);
tupdate(1,1,n,dfn[top[x]],dfn[x],w);
x = f[top[x]];
}
if(d[x] < d[y]) swap(x,y);
tupdate(1,1,n,dfn[y],dfn[x],w);
}
ll query(ll x,ll y){
ll ret = 0;
while(top[x] != top[y]){
if(d[top[x]] < d[top[y]]) swap(x,y);
ret += tquery(1,1,n,dfn[top[x]],dfn[x]);
ret %= p;
x = f[top[x]];
}
if(d[x] < d[y]) swap(x,y);
ret += tquery(1,1,n,dfn[y],dfn[x]);
ret %= p;
return ret;
}
struct Q1{
ll p,flg,nm;
bool operator < (const Q1 &b) const{
return p < b.p;
}
}a[maxn << 1];
struct Q{
ll ans,z;
}q[maxn];
ll cnt;
ll x,y,z,op;
int main(){
// freopen("a.txt","r",stdin);
memset(head,-1,sizeof(head));
n = read(); m = read();
for(ll i = 2; i <= n; ++i){
x = read() + 1;
adde(x,i);
}
dfs1(1,0);dfs2(1,0);tbuild(1,1,n);
for(ll i = 1; i <= m; ++i){
a[++cnt].p = read();a[cnt].flg = 0;a[cnt].nm = i;
a[++cnt].p = read() + 1;a[cnt].flg = 1;a[cnt].nm = i;
q[i].z = read() + 1;
}
sort(a + 1,a + cnt + 1);
cnt = 1;
for(ll i = 0; i <= n; ++i){
update(1,i,1);
while(a[cnt].p == i){
if(!a[cnt].flg) q[a[cnt].nm].ans -= query(1,q[a[cnt].nm].z);
else q[a[cnt].nm].ans += query(1,q[a[cnt].nm].z);
++cnt;
}
}
for(ll i = 1; i <= m; ++i){
printf("%lld\n",(q[i].ans + p) % p);
}
return 0;
}