[模板]树链剖分

题目描述

如题,已知一棵包含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为根节点的子树内所有节点值之和

输入输出格式

输入格式:

 

第一行包含4个正整数N、M、R、P,分别表示树的结点个数、操作个数、根节点序号和取模数(即所有的输出结果均对此取模)。

接下来一行包含N个非负整数,分别依次表示各个节点上初始的数值。

接下来N-1行每行包含两个整数x、y,表示点x和点y之间连有一条边(保证无环且连通)

接下来M行每行包含若干个正整数,每行表示一个操作,格式如下:

操作1: 1 z

操作2: 2 y

操作3: 3 z

操作4: 4 x

输出格式:

 

输出包含若干行,分别依次表示每个操作2或操作4所得的结果(对P取模

输入输出样例

输入样例#1:
5 5 2 24
7 3 7 8 0 
1 2
1 5
3 1
4 1
3 4 2
3 2 2
4 5
1 5 1 3
2 1 3
输出样例#1:
2
21

说明

时空限制:1s,128M

数据规模:

对于100%的数据: N105,M105

所有输入数据在int范围内

 

这道题是用来连树链剖分的,具体的可以看看他人的博客,这里我只放上自己的代码,ac。。

 

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

inline ll read() {
    ll x = 0 , f = 1; char ch = getchar();
    for ( ; !isdigit(ch) ; ch = getchar()) if (ch == '-') f = -1;
    for ( ; isdigit(ch) ; ch = getchar()) x = x * 10 + ch - '0';
    return x * f;
}

const ll maxn = 1e6 + 10;
const ll maxEdge = 2e6 + 10;

struct SegTree {
    ll leftSon , rightSon , weight , LazyTagAdd;
}segTree[maxn << 2];

struct Edge {
    ll u , v , next;
}edge[maxEdge];

ll n , m , r , cnt = 0 , a[maxn] , b[maxn];

ll num = 1 , head[maxn] , _mod;

ll deep[maxn] , fa[maxn] , son[maxn] , tot[maxn] , top[maxn] , idx[maxn];

inline void add_edge(ll from , ll to) {
    edge[num].u = from;
    edge[num].v = to;
    edge[num].next = head[from];
    head[from] = num ++;
}

inline void pushUp(ll root) {
    segTree[root].weight = (segTree[root << 1].weight + segTree[root << 1 | 1].weight) % _mod;
}

inline void pushDown(ll root) {
    segTree[root << 1].LazyTagAdd += segTree[root].LazyTagAdd;
    segTree[root << 1].LazyTagAdd %= _mod;
    
    segTree[root << 1 | 1].LazyTagAdd += segTree[root].LazyTagAdd;
    segTree[root << 1 | 1].LazyTagAdd %= _mod;
    
    segTree[root << 1].weight += segTree[root].LazyTagAdd * (segTree[root << 1].rightSon - segTree[root << 1].leftSon + 1);
    segTree[root << 1].weight %= _mod;
    
    segTree[root << 1 | 1].weight += segTree[root].LazyTagAdd * (segTree[root << 1 | 1].rightSon - segTree[root << 1 | 1].leftSon + 1);
    segTree[root << 1 | 1].weight %= _mod;
    
    segTree[root].LazyTagAdd = 0;
    return ;
}

void build(ll root , ll _left , ll _right) {
    segTree[root].leftSon = _left , segTree[root].rightSon = _right , segTree[root].LazyTagAdd = 0;
    
    if (_left == _right) {
        segTree[root].weight = a[_left];
        return ;
    }
    
    ll _mid = (_left + _right) >> 1;
    build(root << 1 , _left , _mid);
    build(root << 1 | 1 , _mid + 1 , _right);
    
    pushUp(root);
}

ll querySum(ll root , ll _left , ll _right) {
    if (segTree[root].rightSon < _left || _right < segTree[root].leftSon) {
        return 0;
    }
    //cout << root << " " << segTree[root].leftSon << " " << segTree[root].rightSon << " " << segTree[root].weight << endl;
    if (_left <= segTree[root].leftSon && segTree[root].rightSon <= _right) {
        return segTree[root].weight % _mod;
    }
    
    
    if (segTree[root].LazyTagAdd) {
        pushDown(root);
    }
    
    ll _mid = ((segTree[root].leftSon + segTree[root].rightSon) >> 1) , ans = 0;
    if (_left <= _mid) {
        ans += querySum(root << 1 , _left , _right);
        ans %= _mod;
    }
    if (_mid < _right) {
        ans += querySum(root << 1 | 1 , _left , _right);
        ans %= _mod;
    }
    
    return ans;
} 

void addNum(ll root , ll _left , ll _right , ll add) {
    if (segTree[root].rightSon < _left || _right < segTree[root].leftSon) {
        return ;
    }
    
    if (_left <= segTree[root].leftSon && segTree[root].rightSon <= _right) {
        segTree[root].weight += (segTree[root].rightSon - segTree[root].leftSon + 1) * add;
        segTree[root].weight %= _mod;
        
        segTree[root].LazyTagAdd += add;
        segTree[root].LazyTagAdd %= _mod;
        
        return ;
    }
    
    if (segTree[root].LazyTagAdd) {
        pushDown(root);
    }
    
    ll _mid = (segTree[root].leftSon + segTree[root].rightSon) >> 1;
    if (_left <= _mid) {
        addNum(root << 1 , _left , _right , add);
    }
    if (_mid < _right) {
        addNum(root << 1 | 1 , _left , _right , add);
    }
    
    pushUp(root);
    
    return ;
}

ll dfs1(ll now , ll f , ll dep) {
    deep[now] = dep;
    fa[now] = f;
    tot[now] = 1;
    ll maxSon = -1;
    
    for (ll e = head[now] ; e != -1 ; e = edge[e].next) {
        if (edge[e].v == f) {
            continue;
        }
        
        tot[now] += dfs1(edge[e].v , now , dep + 1);
        
        if (tot[edge[e].v] > maxSon) {
            maxSon = tot[edge[e].v];
            son[now] = edge[e].v;
        }
    }
    return tot[now];
}

void dfs2(ll now , ll topf) {
    idx[now] = ++ cnt;
    a[cnt] = b[now];
    top[now] = topf;
    if (!son[now]) {
        return ;
    }
    
    dfs2(son[now] , topf);
    
    for (ll e = head[now] ; e != -1 ; e = edge[e].next) {
        if (!idx[edge[e].v]) {
            dfs2(edge[e].v , edge[e].v);
        }
    }
}

void treeSum(ll x , ll y) {
    ll ans = 0;
    while (top[x] != top[y]) {
        if (deep[top[x]] < deep[top[y]]) {
            swap(x , y);
        }
        ans = (ans + querySum(1 , idx[top[x]] , idx[x])) % _mod;
        x = fa[top[x]];
    }
    
    if (deep[x] > deep[y]) {
        swap(x , y);
    }
    
    ans = (ans + querySum(1 , idx[x] , idx[y])) % _mod;
    
    printf("%lld\n" , ans % _mod);
    
    return ;
}

void treeAdd(ll x , ll y , ll val) {
    while (top[x] != top[y]) {
        if (deep[top[x]] < deep[top[y]]) {
            swap(x , y);
        }
        addNum(1 , idx[top[x]] , idx[x] , val);
        x = fa[top[x]];
    }
    
    if (deep[x] > deep[y]) {
        swap(x , y);
    }
    addNum(1 , idx[x] , idx[y] , val);
}

int main() {
    memset(head , -1 , sizeof(head));
    
    n = read() , m = read() , r = read() , _mod = read();
    for (ll i = 1 ; i <= n ; i ++) {
        b[i] = read();
    }
    
    for (ll i = 1 ; i < n ; i ++) {
        ll x = read() , y = read();
        add_edge(x , y) , add_edge(y , x);
    }
    
    dfs1(r , 0 , 1);
    dfs2(r , r);
    
    build(1 , 1 , n);
    
    while (m --) {
        ll opr = read();
        if (opr == 1) {
            ll x = read() , y = read() , z = read();
            z %= _mod;
            treeAdd(x , y , z);
        }
        else if (opr == 2) {
            ll x = read() , y = read();
            treeSum(x , y);
        }
        else if (opr == 3) {
            ll x = read() , z = read();
            addNum(1 , idx[x] , idx[x] + tot[x] - 1 , z % _mod);
        }
        else if (opr == 4) {
            ll x = read();
            printf("%lld\n" , querySum(1 , idx[x] , idx[x] + tot[x] - 1));
        }
    }
}

 

posted @ 2018-08-27 20:22  Avrora  阅读(151)  评论(0编辑  收藏  举报