码迷,mamicode.com
首页 > 其他好文 > 详细

luogu3384 【模板】树链剖分

时间:2017-12-29 21:49:09      阅读:132      评论:0      收藏:0      [点我收藏+]

标签:def   tin   body   push   namespace   turn   too   cpp   blog   

强烈推荐这篇文章,一下子就看懂AC了。

#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
typedef long long ll;
struct Edge{
    int too, nxt;
}edge[200005];
int n, m, r, p, uu, vv, ww, tt, w[100005], hea[100005], ecnt, dep[100005];
int fa[100005], siz[100005], son[100005], idx[100005], cnt, wt[100005];
int top[100005];
void add_edge(int fro, int too){
    edge[++ecnt].nxt = hea[fro];
    edge[ecnt].too = too;
    hea[fro] = ecnt;
}
void dfs1(int x, int f){
    dep[x] = dep[f] + 1;
    fa[x] = f;
    siz[x] = 1;
    int maxSon=-1;
    for(int i=hea[x]; i; i=edge[i].nxt){
        int t=edge[i].too;
        if(t==f)    continue;
        dfs1(t, x);
        siz[x] += siz[t];
        if(siz[t]>maxSon){
            son[x] = t;
            maxSon = siz[t];
        }
    }
}
void dfs2(int x, int topf){
    idx[x] = ++cnt;
    wt[cnt] = w[x] % p;
    top[x] = topf;
    if(!son[x]) return ;
    dfs2(son[x], topf);
    for(int i=hea[x]; i; i=edge[i].nxt){
        int t=edge[i].too;
        if(t==fa[x] || t==son[x])   continue;
        dfs2(t, t);
    }
}
struct SFT{
    int sum[400005];
    int tag[400005];
    void build(int o, int l, int r){
        if(l==r)    sum[o] = wt[l];
        else{
            int mid=(l+r)>>1;
            int lson=o<<1;
            int rson=lson|1;
            if(l<=mid)  build(lson, l, mid);
            if(mid<r)   build(rson, mid+1, r);
            sum[o] = (sum[lson] + sum[rson]) % p;
        }
    }
    void pushdown(int o, int l, int r, int lson, int rson, int mid){
        tag[lson] = (tag[lson] + tag[o]) % p;
        tag[rson] = (tag[rson] + tag[o]) % p;
        sum[lson] = (sum[lson] + (mid-l+1) * tag[o] % p) % p;
        sum[rson] = (sum[rson] + (r-mid) * tag[o] % p) % p;
        tag[o] = 0;
    }
    void update(int o, int l, int r, int x, int y, int k){
        if(l>=x && r<=y){
            sum[o] = (sum[o] + (r-l+1) * k % p) % p;
            tag[o] = (tag[o] + k) % p;
        }
        else{
            int mid=(l+r)>>1;
            int lson=o<<1;
            int rson=lson|1;
            if(tag[o])  pushdown(o, l, r, lson, rson, mid);
            if(x<=mid)  update(lson, l, mid, x, y, k);
            if(mid<y)   update(rson, mid+1, r, x, y, k);
            sum[o] = (sum[lson] + sum[rson]) % p;
        }
    }
    int query(int o, int l, int r, int x, int y){
        if(l>=x && r<=y)    return sum[o];
        else{
            int mid=(l+r)>>1;
            int lson=o<<1;
            int rson=lson|1;
            int ans=0;
            if(tag[o])  pushdown(o, l, r, lson, rson, mid);
            if(x<=mid)  ans = (ans + query(lson, l, mid, x, y)) % p;
            if(mid<y)   ans = (ans + query(rson, mid+1, r, x, y)) % p;
            return ans;
        }
    }
}sgt;
void updRange(int uu, int vv, int ww){
    ww %= p;
    while(top[uu]!=top[vv]){
        if(dep[top[uu]]<dep[top[vv]])   swap(uu, vv);
        sgt.update(1, 1, n, idx[top[uu]], idx[uu], ww);
        uu = fa[top[uu]];
    }
    if(dep[uu]>dep[vv]) swap(uu, vv);
    sgt.update(1, 1, n, idx[uu], idx[vv], ww);
}
int queryRange(int uu, int vv){
    int ans=0;
    while(top[uu]!=top[vv]){
        if(dep[top[uu]]<dep[top[vv]])   swap(uu, vv);
        ans = (ans + sgt.query(1, 1, n, idx[top[uu]], idx[uu])) % p;
        uu = fa[top[uu]];
    }
    if(dep[uu]>dep[vv]) swap(uu, vv);
    ans = (ans + sgt.query(1, 1, n, idx[uu], idx[vv])) % p;
    return ans;
}
int main(){
    cin>>n>>m>>r>>p;
    for(int i=1; i<=n; i++)
        scanf("%d", &w[i]);
    for(int i=1; i<n; i++){
        scanf("%d %d", &uu, &vv);
        add_edge(uu, vv);
        add_edge(vv, uu);
    }
    dep[r] = 1;
    dfs1(r, 0);
    dfs2(r, r);
    sgt.build(1, 1, n);
    while(m--){
        scanf("%d", &tt);
        if(tt==1){
            scanf("%d %d %d", &uu, &vv, &ww);
            updRange(uu, vv, ww);
        }
        else if(tt==2){
            scanf("%d %d", &uu, &vv);
            printf("%d\n", queryRange(uu, vv));
        }
        else if(tt==3){
            scanf("%d %d", &uu, &ww);
            sgt.update(1, 1, n, idx[uu], idx[uu]+siz[uu]-1, ww);
        }
        else{
            scanf("%d", &uu);
            printf("%d\n", sgt.query(1, 1, n, idx[uu], idx[uu]+siz[uu]-1));
        }
    }
    return 0;
}

luogu3384 【模板】树链剖分

标签:def   tin   body   push   namespace   turn   too   cpp   blog   

原文地址:https://www.cnblogs.com/poorpool/p/8146307.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!