树链剖分

参考博客:
树链剖分详解(洛谷模板 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;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值