zoukankan      html  css  js  c++  java
  • 树剖模板

    树剖要多打

    代码:

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<vector>
    #include<cmath>
    #include<queue>
    #include<map>
    #define inf 2000000000
    #define min(x,y) ((x)<(y)?(x):(y))
    #define max(x,y) ((x)>(y)?(x):(y))
    #define rep(i,a,b) for(int i=(a);i<=(b);++i)
    #define dwn(i,a,b) for(int i=(a);i>=(b);--i)
    using namespace std;
    typedef long long ll;
    const int N=100000;
    int fa[N+10],dep[N+10],sz[N+10],son[N+10],top[N+10],seg[N+10],rev[N+10];
    int n,m,root;
    ll p,num[N+10],add[4*N+10],sum[4*N+10];
    int tot=1,head[N+10];
    struct EDGE
    {
        int to,nxt;
    }edge[2*N+10];
    void add_edge(int u,int v)
    {
        edge[++tot].to=v;
        edge[tot].nxt=head[u];
        head[u]=tot;
    }
    void dfs1(int x,int f)
    {
        sz[x]=1;
        fa[x]=f;
        dep[x]=dep[f]+1;
        for(int i=head[x];i;i=edge[i].nxt)
        {
            int y=edge[i].to;
            if(y!=f)
            {
                dfs1(y,x);
                sz[x]+=sz[y];
                if(sz[y]>sz[son[x]]) son[x]=y;
            }
        }
    }
    void dfs2(int x,int t)
    {
        top[x]=t;
        seg[x]=++seg[0];
        rev[seg[0]]=x;
        if(!son[x]) return;
        dfs2(son[x],t);
        for(int i=head[x];i;i=edge[i].nxt)
        {
            int y=edge[i].to;
            if(y==fa[x]||y==son[x]) continue;
            dfs2(y,y);
        }
    }
    void build(int k,int l,int r)
    {
        if(l==r)
        {
            sum[k]=num[rev[l]];
            return;
        }
        int mid=(l+r)>>1;
        build(k<<1,l,mid);
        build(k<<1|1,mid+1,r);
        sum[k]=(sum[k<<1]+sum[k<<1|1])%p;
    }
    void spread(int k,int l,int r)
    {
        if(add[k])
        {
            int mid=(l+r)>>1;
            sum[k<<1]=(sum[k<<1]+add[k]*(mid-l+1))%p;
            add[k<<1]=(add[k<<1]+add[k])%p;
            sum[k<<1|1]=(sum[k<<1|1]+add[k]*(r-mid))%p;
            add[k<<1|1]=(add[k<<1|1]+add[k])%p;
            add[k]=0;
        }
    }
    void ask_add(int k,int l,int r,int ql,int qr,ll d)
    {
        if(ql<=l&&r<=qr)
        {
            add[k]=(add[k]+d)%p;
            sum[k]=(sum[k]+d*(r-l+1))%p;
            return;
        }
        spread(k,l,r);
        int mid=(l+r)>>1;
        if(ql<=mid) ask_add(k<<1,l,mid,ql,qr,d);
        if(qr>=mid+1) ask_add(k<<1|1,mid+1,r,ql,qr,d);
        sum[k]=(sum[k<<1]+sum[k<<1|1])%p;
    }
    ll ask_sum(int k,int l,int r,int ql,int qr)
    {
        if(ql<=l&&r<=qr)
        {
            return sum[k];
        }
        spread(k,l,r);
        int mid=(l+r)>>1;
        ll val=0;
        if(ql<=mid) val=(val+ask_sum(k<<1,l,mid,ql,qr))%p;
        if(qr>=mid+1) val=(val+ask_sum(k<<1|1,mid+1,r,ql,qr))%p;
        return val;
    }
    ll ask_path(int x,int y,ll d)
    {
        ll val=0;
        int fx=top[x],fy=top[y];
        while(fx!=fy)
        {
            if(dep[fx]>dep[fy]) swap(x,y),swap(fx,fy);
            if(d==0) val=(val+ask_sum(1,1,seg[0],seg[fy],seg[y]))%p;
            else ask_add(1,1,seg[0],seg[fy],seg[y],d);
            y=fa[fy];fy=top[y];
        }
        if(dep[x]>dep[y]) swap(x,y);
        if(d==0)
        {
            val=(val+ask_sum(1,1,seg[0],seg[x],seg[y]))%p;
            return val;
        }
        else
        {
            ask_add(1,1,seg[0],seg[x],seg[y],d);
            return 0;
        }
    }
    int main()
    {
        scanf("%d%d%d%lld",&n,&m,&root,&p);
        rep(i,1,n)
        {
            scanf("%lld",&num[i]);
            num[i]%=p;
        }
        rep(i,1,n-1)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            add_edge(x,y),add_edge(y,x);
        }
        dfs1(root,0);
        dfs2(root,root);
        build(1,1,seg[0]);
        rep(i,1,m)
        {
            int t;
            scanf("%d",&t);
            if(t==1)
            {
                int x,y;ll z;
                scanf("%d%d%lld",&x,&y,&z);
                if(z==0) continue;
                ask_path(x,y,z%p);
            }
            if(t==2)
            {
                int x,y;
                scanf("%d%d",&x,&y);
                printf("%lld
    ",ask_path(x,y,0));
            }
            if(t==3)
            {
                int x;ll z;
                scanf("%d%lld",&x,&z);
                ask_add(1,1,seg[0],seg[x],seg[x]+sz[x]-1,z%p);
            }
            if(t==4)
            {
                int x;
                scanf("%d",&x);
                printf("%lld
    ",ask_sum(1,1,seg[0],seg[x],seg[x]+sz[x]-1));
            }
        }
        return 0;
    }
    
    
  • 相关阅读:
    53. Maximum Subarray
    64. Minimum Path Sum
    28. Implement strStr()
    26. Remove Duplicates from Sorted Array
    21. Merge Two Sorted Lists
    14. Longest Common Prefix
    7. Reverse Integer
    412. Fizz Buzz
    linux_修改域名(centos)
    linux_redis常用数据类型操作
  • 原文地址:https://www.cnblogs.com/MYsBlogs/p/11151732.html
Copyright © 2011-2022 走看看