1. 程式人生 > >luogu3384 【模板】樹鏈剖分

luogu3384 【模板】樹鏈剖分

psu 連通 highlight scripts text font 序號 操作 del

P3384 【模板】樹鏈剖分

題目描述

如題,已知一棵包含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 x y z

操作2: 2 x y

操作3: 3 x 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

數據規模:

對於30%的數據: N \leq 10, M \leq 10N10,M10

對於70%的數據: N \leq {10}^3, M \leq {10}^3N10?3??,M10?3??

對於100%的數據: N \leq {10}^5, M \leq {10}^5N10?5??,M10?5??

其實,純隨機生成的樹LCA+暴力是能過的,可是,你覺得可能是純隨機的麽233

樣例說明:

樹的結構如下:

技術分享

各個操作如下:

技術分享

故輸出應依次為2、21(重要的事情說三遍:記得取模)

模板題就不多說啦,http://blog.sina.com.cn/s/blog_6974c8b20100zc61.html 有介紹,我就是看這個懂得

#include <algorithm>
#include <cstdio>
#include <vector>
using namespace std;
const int maxn = 100000 + 10;
int cnt = 0,map[maxn],val[maxn],num[maxn],size[maxn],father[maxn],son[maxn],top[maxn],dep[maxn],w[maxn];
int n,m,r,p;
vector<int> edges[maxn];
inline void dfs1(int now,int f) {
    size[now] = 1;
    father[now] = f;
    dep[now] = dep[father[now]]+1;
    for (size_t i = 0;i < edges[now].size();i++)
        if (edges[now][i] != f) {
            dfs1(edges[now][i],now);
            size[now] += size[edges[now][i]];
            if (size[son[now]] < size[edges[now][i]] || !son[now]) son[now] = edges[now][i];
        }
}
inline void dfs2(int now,int ntop) {
    top[now] = ntop;
    num[now] = ++cnt;
    map[num[now]] = now;
    if (son[now]) dfs2(son[now],ntop);
    for (size_t i = 0;i < edges[now].size();i++)
        if (edges[now][i] != father[now] && edges[now][i] != son[now]) dfs2(edges[now][i],edges[now][i]);
}
struct seg { long long sum,mark,l,r; } tree[maxn*4];
inline void BuildTree(int l,int r,int root) {
    if (l == r) {
        tree[root].l = l;
        tree[root].r = r;
        tree[root].sum = val[map[l]];
        tree[root].mark = 0;
        return;
    }
    int mid = l+r>>1;
    BuildTree(l,mid,root<<1);
    BuildTree(mid+1,r,(root<<1)+1);
    tree[root].l = l;
    tree[root].r = r;
    tree[root].mark = 0;
    tree[root].sum = tree[root<<1].sum+tree[(root<<1)+1].sum;
}
inline void pushdown(int root) {
    if (tree[root].mark) {
        tree[root<<1].mark += tree[root].mark;
        tree[root<<1|1].mark += tree[root].mark;
        tree[root<<1].sum += tree[root].mark*(tree[root<<1].r-tree[root<<1].l+1);
        tree[root<<1|1].sum += tree[root].mark*(tree[root<<1|1].r-tree[root<<1|1].l+1);
        tree[root].mark = 0;
    }
}
inline void Update(int l,int r,int ql,int qr,int root,long long x) {
    if (ql > r || qr < l) return;
    if (ql <= l && qr >= r) {
        tree[root].mark += x;
        tree[root].sum += x*(r-l+1);
        return;
    }
    pushdown(root);
    int mid = l+r>>1;
    Update(l,mid,ql,qr,root<<1,x);
    Update(mid+1,r,ql,qr,root<<1|1,x);
    tree[root].sum = tree[root<<1].sum+tree[root<<1|1].sum;
}
inline long long Query(int l,int r,int ql,int qr,int root) {
    if (ql > r || qr < l) return 0;
    if (ql <= l && qr >= r) return tree[root].sum;
    pushdown(root);
    int mid = l+r>>1;
    return Query(l,mid,ql,qr,root<<1)+Query(mid+1,r,ql,qr,root<<1|1);
}
inline void UpdateEdges(int u,int v,long long x) {
    int topu = top[u];
    int topv = top[v];
    while (topu != topv) {
        if (dep[topu] < dep[topv]) {
            swap(topu,topv);
            swap(u,v);
        }
        Update(1,cnt,num[topu],num[u],1,x);
        u = father[topu];
        topu = top[u];
    }
    if (dep[u] > dep[v]) swap(u,v);
    Update(1,cnt,num[u],num[v],1,x);
}
inline long long QueryEdges(int u,int v) {
    int topu = top[u];
    int topv = top[v];
    long long sum = 0;
    while (topu != topv) {
        if (dep[topu] < dep[topv]) {
            swap(topu,topv);
            swap(u,v);
        }
        sum += Query(1,cnt,num[topu],num[u],1);
        sum %= p;
        u = father[topu];
        topu = top[u];
    }
    if (dep[u] > dep[v]) swap(u,v);
    return (sum+Query(1,cnt,num[u],num[v],1))%p;
}
int main() {
    scanf("%d%d%d%d",&n,&m,&r,&p);
    for (int i = 1;i <= n;i++) scanf("%d",&val[i]);
    for (int i = 1,u,v;i < n;i++) {
        scanf("%d%d",&u,&v);
        edges[u].push_back(v);
        edges[v].push_back(u);
    }
    dfs1(r,0);
    dfs2(r,r);
    BuildTree(1,cnt,1);
    while (m--) {
        long long dispose,x,y;
        scanf("%lld%lld",&dispose,&x);
        if (dispose == 1) {
            long long z;
            scanf("%lld%lld",&y,&z);
            UpdateEdges(x,y,z);
        } else if (dispose == 2) {
            scanf("%lld",&y);
            printf("%lld\n",QueryEdges(x,y));
        } else if (dispose == 3) {
            scanf("%lld",&y);
            Update(1,cnt,num[x],num[x]+size[x]-1,1,y);
        } else printf("%lld\n",Query(1,cnt,num[x],num[x]+size[x]-1,1)%p);
    }
    return 0;
}

  

luogu3384 【模板】樹鏈剖分