参考博客:
树链剖分详解(洛谷模板 P3384)
树链剖分详解
题目:P3384 【模板】树链剖分
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define mid ((l+r)>>1)
#define lson rt<<1, l, mid
#define rson rt<<1|1, mid+1, r
#define len (r-l+1)
#define Temp template<typename T>
#define len (r-l+1)
Temp inline void read(T &x)
{
x = 0;
T w = 1, ch = getchar();
while(!isdigit(ch) && ch!= '-')ch = getchar();
if(ch == '-')w = -1, ch = getchar();
while(isdigit(ch))x = (x<<3)+(x<<1)+(ch^'0'),ch = getchar();
x = x * w;
}
const int maxn=300000+10;
int n, m, r, mod;
int e, beg[maxn], nex[maxn], to[maxn], w[maxn], wt[maxn];
//链式前向星
int a[maxn<<2], laz[maxn<<2];
//线段树
int son[maxn], id[maxn], fa[maxn], cnt = 0, dep[maxn], siz[maxn],top[maxn];
//son重儿子,id新的编号,fa父亲节点,dep深度,siz子树大小,top当前顶端节点
int res = 0;
inline void add(int x, int y)
{
to[++e] = y;
nex[e] = beg[x];
beg[x] = e;
}
inline void pushdown(int rt, int lenn)
{
laz[rt<<1] += laz[rt];
laz[rt<<1|1] += laz[rt];
a[rt<<1] += laz[rt]*(lenn -(lenn>>1));
a[rt<<1|1] += laz[rt]*(lenn>>1);
a[rt<<1] %= mod;
a[rt<<1|1] %= mod;
laz[rt] = 0;
}
inline void build(int rt, int l, int r)
{
if(l == r)
{
a[rt] = wt[l];
if(a[rt] > mod) a[rt] %= mod;
return;
}
build(lson);
build(rson);
a[rt] = (a[rt<<1]+a[rt<<1|1])%mod;
}
inline void query(int rt, int l, int r, int L, int R)
{
if(L <= l && r <= R)
{
res += a[rt];
res %= mod;
return;
}
else
{
if(laz[rt])pushdown(rt, len);
if(L <= mid)query(lson, L, R);
if(R > mid)query(rson, L, R);
}
}
inline void update(int rt, int l, int r, int L, int R, int k)
{
if(L <= l && r<= R)
{
laz[rt] += k;
a[rt] += k * len;
}
else
{
if(laz[rt])pushdown(rt, len);
if(L <= mid)update(lson, L, R, k);
if(R > mid)update(rson, L, R, k);
a[rt] = (a[rt<<1]+a[rt<<1|1]) % mod;
}
}
inline int qRange(int x, int y)
{
int ans = 0;
while(top[x] != top[y])
{
if(dep[top[x]] < dep[top[y]])swap(x, y);
res = 0;
query(1, 1, n, id[top[x]], id[x]);
ans += res;
ans %= mod;
x = fa[top[x]];
}
if(dep[x] > dep[y])swap(x, y);
res = 0;
query(1, 1, n, id[x], id[y]);
ans += res;
return ans % mod;
}
inline void updRange(int x, int y, int k)
{
k %= mod;
while(top[x] != top[y])
{
if(dep[top[x]] < dep[top[y]])swap(x, y);
update(1, 1, n, id[top[x]], id[x], k);
x = fa[top[x]];
}
if(dep[x] > dep[y])swap(x, y);
update(1, 1, n, id[x], id[y], k);
}
inline int qson(int x)
{
res = 0;
query(1, 1, n, id[x], id[x]+siz[x]-1);
return res;
}
inline void updson(int x, int k)
{
update(1, 1, n,id[x], id[x]+siz[x]-1, k);
}
inline void dfs1(int x, int f, int deep)
{
dep[x] = deep;
fa[x] = f;
siz[x] = 1;
int maxson = -1;
for(int i = beg[x]; i; i = nex[i])
{
int y = to[i];
if(y == f)continue;
dfs1(y, x, deep+1);
siz[x] += siz[y];
if(siz[y] > maxson)son[x] = y,maxson = siz[y];
}
}
inline void dfs2(int x, int topf)
{
id[x] = ++cnt;
wt[cnt] = w[x];
top[x] = topf;
if(!son[x])return;
dfs2(son[x], topf);
for(int i = beg[x]; i ; i = nex[i])
{
int y = to[i];
if(y == fa[x] || y == son[x])continue;
dfs2(y, y);
}
}
int main()
{
read(n), read(m), read(r), read(mod);
for(int i = 1; i <= n; i++)read(w[i]);
for(int i = 1; i < n; i++)
{
int a, b;
read(a);
read(b);
add(a, b), add(b, a);
}
dfs1(r, 0, 1);
dfs2(r, r);
build(1, 1, n);
while(m--)
{
int k, x, y, z;
read(k);
if(k == 1)
{
read(x);
read(y);
read(z);
updRange(x, y, z);
}
else if(k == 2)
{
read(x);
read(y);
printf("%d\n", qRange(x, y));
}
else if(k == 3)
{
read(x);
read(y);
updson(x, y);
}
else
{
read(x);
printf("%d\n", qson(x));
}
}
return 0;
}
题目:Water Tree
题意:就是给你一个根节点为1的数,然后给你三种操作,1 x是把这个节点x,及其子树权值置为1,2 x是把x及其所有的祖先节点的权值位置1, 3 x 是查询x节点的权值0,还是1。
思路:本题没有什么特别好的思路就是树链剖分的板题,如果仅仅是修改子树完全可以用dfs序,但是修改祖先节点就不好修改了。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define mid ((l+r)>>1)
#define lson rt<<1, l, mid
#define rson rt<<1|1, mid+1, r
#define len (r-l+1)
#define Temp template<typename T>
#define len (r-l+1)
Temp inline void read(T &x)
{
x = 0;
T w = 1, ch = getchar();
while(!isdigit(ch) && ch!= '-')ch = getchar();
if(ch == '-')w = -1, ch = getchar();
while(isdigit(ch))x = (x<<3)+(x<<1)+(ch^'0'),ch = getchar();
x = x * w;
}
const int maxn=500000+10;
int n, m, r;
int e, beg[maxn<<1], nex[maxn<<1], to[maxn<<1], w[maxn], wt[maxn];
int st[maxn<<2], laz[maxn<<2];
int son[maxn], id[maxn], fa[maxn], cnt = 0, dep[maxn], siz[maxn],top[maxn];
int res = 0;
inline void add(int x, int y)
{
to[++e] = y;
nex[e] = beg[x];
beg[x] = e;
}
void build(int o, int l, int r){
if(l == r)st[o] = 0;
else {
int m = l + ((r-l)>>1);
build(o<<1, l, m);
build(o<<1|1, m+1, r);
st[o] = st[o<<1] + st[o<<1|1];
}
}
void pushup(int o){
st[o]=st[o<<1]+st[o<<1|1];
}
void pushdown(int o,int l,int r){
if(laz[o] != -1){//注意这块,很多模板默认为0,因为采用线段树的延迟标记,0的延迟标记下不来,所以改成-1;
int c=laz[o];
laz[o<<1]=c;
laz[o<<1|1]=c;
int m=l+((r-l)>>1);
st[o<<1]=(m-l+1)*c;
st[o<<1|1]=(r-m)*c;
laz[o]=-1;
}
}
void update(int o,int l,int r,int ql,int qr,int c){
if(ql<=l&&qr>=r){
laz[o]=c;
st[o]=(r-l+1)*c;
return;
}
pushdown(o,l,r);
int m=l+((r-l)>>1);
if(ql<=m)update(o<<1,l,m,ql,qr,c);
if(qr>=m+1)update(o<<1|1,m+1,r,ql,qr,c);
pushup(o);
}
int query(int o,int l,int r,int ql,int qr){
if(ql<=l&&qr>=r) return st[o];
pushdown(o,l,r);
int m=l+((r-l)>>1);
int ans=0;
if(ql<=m)ans+=query(o<<1,l,m,ql,qr);
if(qr>=m+1)ans+=query(o<<1|1,m+1,r,ql,qr);
return ans;
}
inline void updRange(int x, int k)
{
while(top[x] != 1)
{
update(1, 1, n, id[top[x]], id[x], k);
x = fa[top[x]];
}
update(1, 1, n, 1, id[x], k);
}
inline void updson(int x, int k)
{
update(1, 1, n,id[x], id[x]+siz[x]-1, k);
}
inline void dfs1(int x, int f, int deep)
{
dep[x] = deep;
fa[x] = f;
siz[x] = 1;
int maxson = -1;
for(int i = beg[x]; i; i = nex[i])
{
int y = to[i];
if(y == f)continue;
dfs1(y, x, deep+1);
siz[x] += siz[y];
if(siz[y] > maxson)son[x] = y,maxson = siz[y];
}
}
inline void dfs2(int x, int topf)
{
id[x] = ++cnt;
wt[cnt] = w[x];
top[x] = topf;
if(!son[x])return;
dfs2(son[x], topf);
for(int i = beg[x]; i ; i = nex[i])
{
int y = to[i];
if(y == fa[x] || y == son[x])continue;
dfs2(y, y);
}
}
int main()
{
read(n);
for(int i = 1; i < n; i++)
{
int a, b;
read(a);
read(b);
add(a, b), add(b, a);
}
memset(laz, -1, sizeof laz);
dfs1(1, 0, 1);
dfs2(1, 1);
build(1, 1, n);
read(m);
while(m--){
int op, v;
read(op), read(v);
if(op == 1)updson(v, 1);
else if(op == 2)updRange(v, 0);
else printf("%d\n", query(1, 1, n, id[v], id[v]));
}
return 0;
}