名称 | 解释 |
---|---|
f [ u ] f[u] f[u] | 保存结点 u u u 的父亲节点 |
d e p [ u ] dep[u] dep[u] | 保存结点 u u u 的深度值 |
s i z e [ u ] size[u] size[u] | 保存以 u u u 为根的子树节点个数 |
s o n [ u ] son[u] son[u] | 保存重儿子 |
r k [ u ] rk[u] rk[u] | 保存当前 d f s dfs dfs 标号在树中所对应的节点 |
t o p [ u ] top[u] top[u] | 保存当前节点所在链的顶端节点(替代 l c a lca lca) |
i d [ u ] id[u] id[u] | 保存树中每个节点剖分以后的新编号( D F S DFS DFS的执行顺序) |
模板:
#include<bits/stdc++.h>
#define rint register int
#define deb(x) cerr<<#x<<" = "<<(x)<<'\n';
using namespace std;
typedef long long ll;
typedef pair <int,int> pii;
ll mod = 1e9 + 7;
const int maxn = 3e5 + 10;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define pushup(rt) t[rt] = t[rt<<1] + t[rt<<1|1];
ll t[maxn<<2], lazy[maxn<<2], a[maxn];
int n, m, f[maxn], size[maxn];
int cnt, head[maxn], dep[maxn];
int rk[maxn], rks, id[maxn];
int son[maxn], top[maxn];
struct EDGE {
int next, to, w;
} edge[maxn<<2];
void add(int u, int v, int w) {
edge[++cnt].next = head[u];
edge[cnt].to = v;
edge[cnt].w = w;
head[u] = cnt;
}
/*-------------------------树剖-------------------------*/
void dfs1(int cur, int fa, int de){
dep[cur] = de, f[cur] = fa, size[cur] = 1;
for(int i=head[cur]; i; i=edge[i].next){
int v = edge[i].to;
if(v == fa) continue;
dfs1(v, cur, de+1);
size[cur] += size[v];
if(size[son[cur]] < size[v]) son[cur] = v;
}
}
void dfs2(int cur, int tp){
top[cur] = tp, id[cur] = ++rks, rk[rks] = cur;
if(son[cur]) dfs2(son[cur], tp);
for(int i=head[cur]; i; i=edge[i].next){
int v = edge[i].to;
if(v == f[cur]) continue;
if(v != son[cur]) dfs2(v, v);
}
}
/*-------------------------树剖-------------------------*/
/*-------------------------线段树-------------------------*/
void build(int l,int r,int rt){
lazy[rt] = 0;
if(l==r){
t[rt] = a[rk[l]];
return ;
}
int m = l + r >> 1;
build(lson);
build(rson);
pushup(rt);
}
void pushdown(int l,int r,int rt) {
if(lazy[rt]) {
lazy[rt<<1] += lazy[rt];
lazy[rt<<1|1] += lazy[rt];
t[rt<<1] += l*lazy[rt];
t[rt<<1|1] += r*lazy[rt];
lazy[rt] = 0;
}
}
void update(int L,int R,int C,int l,int r,int rt) {
if(L<=l&&r<=R) {
t[rt] += (r-l+1)*C;
lazy[rt] += C;
return ;
}
int m = (l+r)>>1;
pushdown(m-l+1,r-m,rt);
if(L<=m) update(L,R,C,lson);
if(R>m) update(L,R,C,rson);
pushup(rt);
}
ll query(int L,int R,int l,int r,int rt) {
if(L<=l&&r<=R) return t[rt];
int m = (l+r)>>1;
pushdown(m-l+1,r-m,rt);
ll ans = 0;
if(L<=m) ans += query(L,R,lson);
if(R>m) ans += query(L,R,rson);
return ans;
}
/*-------------------------线段树-------------------------*/
/*----------------------树剖 + 线段树----------------------*/
ll sum(int x, int y){
ll ret = 0;
while(top[x] ^ top[y]){
if(dep[top[x]]<dep[top[y]]) swap(x, y);
ret += query(id[top[x]],id[x],1,n,1);
x = f[top[x]];
}
if(id[x]>id[y]) swap(x, y);
return ret + query(id[x],id[y],1,n,1);
}
void updates(int x, int y, int c){
while(top[x] ^ top[y]){
if(dep[top[x]]<dep[top[y]]) swap(x, y);
update(id[top[x]],id[x],c,1,n,1);
x = f[top[x]];
}
if(id[x]>id[y]) swap(x, y);
update(id[x],id[y],c,1,n,1);
}
/*----------------------树剖 + 线段树----------------------*/
int main() {
int rt;
scanf("%d%d%d%d", &n, &m, &rt, &mod);
for(int i=1; i<=n; i++) scanf("%d", a+i);
for(int i=1; i<n; i++){
int u, v;
scanf("%d%d", &u, &v);
add(u, v, 1);
add(v, u, 1);
}
dfs1(rt, 0, 1);
dfs2(rt, rt);
build(1, n, 1);
for(int i=1; i<=m; i++){
int x, y, c, op;
scanf("%d", &op);
if(op == 1){
scanf("%d%d%d", &x, &y, &c);
updates(x, y, c);
}
else if(op == 2){
scanf("%d%d", &x, &y);
printf("%lld\n", sum(x, y));
}
else if(op == 3){
scanf("%d%d", &x, &c);
update(id[x],id[x]+size[x]-1,c,1,n,1);
}
else {
scanf("%d", &x);
printf("%lld\n", query(id[x],id[x]+size[x]-1,1,n,1));
}
}
}
模板题:洛谷 P3384
#include<bits/stdc++.h>
#define rint register int
#define deb(x) cerr<<#x<<" = "<<(x)<<'\n';
using namespace std;
typedef long long ll;
typedef pair <int,int> pii;
ll mod = 1e9 + 7;
const int maxn = 3e5 + 10;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define pushup(rt) t[rt] = (t[rt<<1] + t[rt<<1|1]) % mod;
ll t[maxn<<2], lazy[maxn<<2], a[maxn];
int n, m, f[maxn], size[maxn];
int cnt, head[maxn], dep[maxn];
int rk[maxn], rks, id[maxn];
int son[maxn], top[maxn];
struct EDGE {
int next, to, w;
} edge[maxn<<2];
void add(int u, int v, int w) {
edge[++cnt].next = head[u];
edge[cnt].to = v;
edge[cnt].w = w;
head[u] = cnt;
}
/*-------------------------树剖-------------------------*/
void dfs1(int cur, int fa, int de){
dep[cur] = de, f[cur] = fa, size[cur] = 1;
for(int i=head[cur]; i; i=edge[i].next){
int v = edge[i].to;
if(v == fa) continue;
dfs1(v, cur, de+1);
size[cur] += size[v];
if(size[son[cur]] < size[v]) son[cur] = v;
}
}
void dfs2(int cur, int tp){
top[cur] = tp, id[cur] = ++rks, rk[rks] = cur;
if(son[cur]) dfs2(son[cur], tp);
for(int i=head[cur]; i; i=edge[i].next){
int v = edge[i].to;
if(v == f[cur]) continue;
if(v != son[cur]) dfs2(v, v);
}
}
/*-------------------------树剖-------------------------*/
/*-------------------------线段树-------------------------*/
void build(int l,int r,int rt){
lazy[rt] = 0;
if(l==r){
t[rt] = a[rk[l]];
return ;
}
int m = l + r >> 1;
build(lson);
build(rson);
pushup(rt);
}
void pushdown(int l,int r,int rt) {
if(lazy[rt]) {
(lazy[rt<<1] += lazy[rt]) %= mod;
(lazy[rt<<1|1] += lazy[rt]) %= mod;
(t[rt<<1] += l*lazy[rt]) %= mod;
(t[rt<<1|1] += r*lazy[rt]) %= mod;
lazy[rt] = 0;
}
}
void update(int L,int R,int C,int l,int r,int rt) {
if(L<=l&&r<=R) {
(t[rt] += (r-l+1)*C) %= mod;
(lazy[rt] += C) %= mod;
return ;
}
int m = (l+r)>>1;
pushdown(m-l+1,r-m,rt);
if(L<=m) update(L,R,C,lson);
if(R>m) update(L,R,C,rson);
pushup(rt);
}
int query(int L,int R,int l,int r,int rt) {
if(L<=l&&r<=R) return t[rt];
int m = (l+r)>>1;
pushdown(m-l+1,r-m,rt);
ll ans = 0;
if(L<=m) ans += query(L,R,lson);
if(R>m) ans += query(L,R,rson);
return ans % mod;
}
/*-------------------------线段树-------------------------*/
/*----------------------树剖 + 线段树----------------------*/
int sum(int x, int y){
int ret = 0;
while(top[x] ^ top[y]){
if(dep[top[x]]<dep[top[y]]) swap(x, y);
(ret += query(id[top[x]],id[x],1,n,1)) %= mod;
x = f[top[x]];
}
if(id[x]>id[y]) swap(x, y);
return (ret + query(id[x],id[y],1,n,1)) % mod;
}
void updates(int x, int y, int c){
while(top[x] ^ top[y]){
if(dep[top[x]]<dep[top[y]]) swap(x, y);
update(id[top[x]],id[x],c,1,n,1);
x = f[top[x]];
}
if(id[x]>id[y]) swap(x, y);
update(id[x],id[y],c,1,n,1);
}
/*----------------------树剖 + 线段树----------------------*/
int main() {
int rt;
scanf("%d%d%d%d", &n, &m, &rt, &mod);
for(int i=1; i<=n; i++) scanf("%d", a+i);
for(int i=1; i<n; i++){
int u, v;
scanf("%d%d", &u, &v);
add(u, v, 1);
add(v, u, 1);
}
dfs1(rt, 0, 1);
dfs2(rt, rt);
build(1, n, 1);
for(int i=1; i<=m; i++){
int x, y, c, op;
scanf("%d", &op);
if(op == 1){
scanf("%d%d%d", &x, &y, &c);
updates(x, y, c);
}
else if(op == 2){
scanf("%d%d", &x, &y);
printf("%d\n", sum(x, y));
}
else if(op == 3){
scanf("%d%d", &x, &c);
update(id[x],id[x]+size[x]-1,c,1,n,1);
}
else {
scanf("%d", &x);
printf("%d\n", query(id[x],id[x]+size[x]-1,1,n,1));
}
}
}
例题一:洛谷 P2146 软件包管理器
安装软件包
x
x
x:计算从根节点到
x
x
x 的路径和
卸载软件包
x
x
x:计算
x
x
x 的所有子树节点权值和
#include<bits/stdc++.h>
#define rint register int
#define deb(x) cerr<<#x<<" = "<<(x)<<'\n';
using namespace std;
typedef long long ll;
typedef pair <int,int> pii;
ll mod = 1e9 + 7;
const int maxn = 3e5 + 10;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define pushup(rt) t[rt] = t[rt<<1] + t[rt<<1|1];
ll t[maxn<<2], lazy[maxn<<2], a[maxn];
int n, m, f[maxn], size[maxn];
int cnt, head[maxn], dep[maxn];
int rk[maxn], rks, id[maxn];
int son[maxn], top[maxn];
struct EDGE {
int next, to, w;
} edge[maxn<<2];
void add(int u, int v, int w) {
edge[++cnt].next = head[u];
edge[cnt].to = v;
edge[cnt].w = w;
head[u] = cnt;
}
/*-------------------------树剖-------------------------*/
void dfs1(int cur, int fa, int de){
dep[cur] = de, f[cur] = fa, size[cur] = 1;
for(int i=head[cur]; i; i=edge[i].next){
int v = edge[i].to;
if(v == fa) continue;
dfs1(v, cur, de+1);
size[cur] += size[v];
if(size[son[cur]] < size[v]) son[cur] = v;
}
}
void dfs2(int cur, int tp){
top[cur] = tp, id[cur] = ++rks, rk[rks] = cur;
if(son[cur]) dfs2(son[cur], tp);
for(int i=head[cur]; i; i=edge[i].next){
int v = edge[i].to;
if(v == f[cur]) continue;
if(v != son[cur]) dfs2(v, v);
}
}
/*-------------------------树剖-------------------------*/
/*-------------------------线段树-------------------------*/
void build(int l,int r,int rt){
lazy[rt] = -1;
if(l==r){
t[rt] = 0;
return ;
}
int m = l + r >> 1;
build(lson);
build(rson);
pushup(rt);
}
void pushdown(int l,int r,int rt) {
if(lazy[rt]!=-1) {
lazy[rt<<1] = lazy[rt];
lazy[rt<<1|1] = lazy[rt];
t[rt<<1] = l*lazy[rt];
t[rt<<1|1] = r*lazy[rt];
lazy[rt] = -1;
}
}
void update(int L,int R,int C,int l,int r,int rt) {
if(L<=l&&r<=R) {
t[rt] = (r-l+1)*C;
lazy[rt] = C;
return ;
}
int m = (l+r)>>1;
pushdown(m-l+1,r-m,rt);
if(L<=m) update(L,R,C,lson);
if(R>m) update(L,R,C,rson);
pushup(rt);
}
int query(int L,int R,int l,int r,int rt) {
if(L<=l&&r<=R) return t[rt];
int m = (l+r)>>1;
pushdown(m-l+1,r-m,rt);
ll ans = 0;
if(L<=m) ans += query(L,R,lson);
if(R>m) ans += query(L,R,rson);
return ans;
}
/*-------------------------线段树-------------------------*/
/*----------------------树剖 + 线段树----------------------*/
void updates(int x, int y, int c){
while(top[x] ^ top[y]){
if(dep[top[x]]<dep[top[y]]) swap(x, y);
update(id[top[x]],id[x],c,1,n,1);
x = f[top[x]];
}
if(id[x]>id[y]) swap(x, y);
update(id[x],id[y],c,1,n,1);
}
/*----------------------树剖 + 线段树----------------------*/
int main() {
scanf("%d", &n);
for(int i=2; i<=n; i++){
int v;
scanf("%d", &v);
v++;
add(i, v, 1);
add(v, i, 1);
}
dfs1(1, 0, 1);
dfs2(1, 1);
build(1, n, 1);
scanf("%d", &m);
for(int i=1; i<=m; i++){
int x;
char op[20];
int t1 = t[1];
scanf("%s%d", op, &x);
x++;
if(op[0] == 'i'){
updates(1, x, 1);
printf("%d\n", t[1] - t1);
}
else {
printf("%d\n", query(id[x],id[x]+size[x]-1,1,n,1));
update(id[x],id[x]+size[x]-1,0,1,n,1);
}
}
}
例题二:洛谷 P2590 树的统计
#include<bits/stdc++.h>
#define rint register int
#define deb(x) cerr<<#x<<" = "<<(x)<<'\n';
using namespace std;
typedef long long ll;
typedef pair <int,int> pii;
const int maxn = 3e5 + 10;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
ll t1[maxn<<2], t2[maxn<<2], a[maxn];
int n, m, f[maxn], size[maxn];
int cnt, head[maxn], dep[maxn];
int rk[maxn], rks, id[maxn];
int son[maxn], top[maxn];
struct EDGE {
int next, to, w;
} edge[maxn<<2];
void add(int u, int v, int w) {
edge[++cnt].next = head[u];
edge[cnt].to = v;
edge[cnt].w = w;
head[u] = cnt;
}
/*-------------------------树剖-------------------------*/
void dfs1(int cur, int fa, int de){
dep[cur] = de, f[cur] = fa, size[cur] = 1;
for(int i=head[cur]; i; i=edge[i].next){
int v = edge[i].to;
if(v == fa) continue;
dfs1(v, cur, de+1);
size[cur] += size[v];
if(size[son[cur]] < size[v]) son[cur] = v;
}
}
void dfs2(int cur, int tp){
top[cur] = tp, id[cur] = ++rks, rk[rks] = cur;
if(son[cur]) dfs2(son[cur], tp);
for(int i=head[cur]; i; i=edge[i].next){
int v = edge[i].to;
if(v == f[cur]) continue;
if(v != son[cur]) dfs2(v, v);
}
}
/*-------------------------树剖-------------------------*/
/*-------------------------线段树-------------------------*/
void pushup(int rt){
t1[rt] = t1[rt<<1] + t1[rt<<1|1];
t2[rt] = max(t2[rt<<1], t2[rt<<1|1]);
}
void build(int l,int r,int rt){
if(l==r){
t1[rt] = t2[rt] = a[rk[l]];
return ;
}
int m = l + r >> 1;
build(lson);
build(rson);
pushup(rt);
}
void update(int L,int R,int C,int l,int r,int rt) {
if(L<=l&&r<=R) {
t1[rt] = (r-l+1)*C;
t2[rt] = C;
return ;
}
int m = (l+r)>>1;
if(L<=m) update(L,R,C,lson);
if(R>m) update(L,R,C,rson);
pushup(rt);
}
ll query1(int L,int R,int l,int r,int rt) {
if(L<=l&&r<=R) return t2[rt];
int m = (l+r)>>1;
ll ans = -1e10;
if(L<=m) ans = max(ans, query1(L,R,lson));
if(R>m) ans = max(ans, query1(L,R,rson));
return ans;
}
ll query2(int L,int R,int l,int r,int rt) {
if(L<=l&&r<=R) return t1[rt];
int m = (l+r)>>1;
ll ans = 0;
if(L<=m) ans += query2(L,R,lson);
if(R>m) ans += query2(L,R,rson);
return ans;
}
/*-------------------------线段树-------------------------*/
/*----------------------树剖 + 线段树----------------------*/
ll sum1(int x, int y){
ll ret = -1e10;
while(top[x] ^ top[y]){
if(dep[top[x]]<dep[top[y]]) swap(x, y);
ret = max(ret, query1(id[top[x]],id[x],1,n,1));
x = f[top[x]];
}
if(id[x]>id[y]) swap(x, y);
return max(ret, query1(id[x],id[y],1,n,1));
}
ll sum2(int x, int y){
ll ret = 0;
while(top[x] ^ top[y]){
if(dep[top[x]]<dep[top[y]]) swap(x, y);
ret += query2(id[top[x]],id[x],1,n,1);
x = f[top[x]];
}
if(id[x]>id[y]) swap(x, y);
return ret + query2(id[x],id[y],1,n,1);
}
void updates(int x, int y, int c){
while(top[x] ^ top[y]){
if(dep[top[x]]<dep[top[y]]) swap(x, y);
update(id[top[x]],id[x],c,1,n,1);
x = f[top[x]];
}
if(id[x]>id[y]) swap(x, y);
update(id[x],id[y],c,1,n,1);
}
/*----------------------树剖 + 线段树----------------------*/
int main() {
scanf("%d", &n);
for(int i=1; i<n; i++){
int u, v;
scanf("%d%d", &u, &v);
add(u, v, 1);
add(v, u, 1);
}
for(int i=1; i<=n; i++) scanf("%lld", a+i);
dfs1(1, 0, 1);
dfs2(1, 1);
build(1, n, 1);
scanf("%d", &m);
for(int i=1; i<=m; i++){
char s[10];
int x, y;
scanf("%s%d%d", s, &x, &y);
if(s[1] == 'H') updates(x, x, y);
else if(s[1] == 'M') printf("%lld\n", sum1(x, y));
else if(s[1] == 'S') printf("%lld\n", sum2(x, y));
}
}