p3384 树链剖分模板题

树链剖分的代码实在是长,少有的几次代码行数过百了

线段树 在图论里面的应用
线段树是处理区间问题的
在图论的树里面的应用就是通过重链的方式dfs编号,形成一段连续的区间,就可以用线段树来处理了;
能做到的事情为
如题,已知一棵包含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为根节点的子树内所有节点值之和

#include 
#include 
#include 

using namespace std;
const int maxn=1e5+7;
struct node{
    int l,r,sum,lazy;
}seg[maxn<<2];
int h[maxn],e[maxn<<1],ne[maxn<<1],idx;
int w[maxn],id[maxn],cnt,w2[maxn],deep[maxn],fa[maxn],siz[maxn],son[maxn],top[maxn];
int n,m,root,mod;

void add(int a,int b){
    e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
void dfs1(int x,int f){
    deep[x]=deep[f]+1,fa[x]=f,siz[x]=1;
    int max_son=-1;
    for(int i=h[x];~i;i=ne[i]){
        int j=e[i];if(j==f)continue;
        dfs1(j,x);siz[x]+=siz[j];
        if(siz[j]>max_son)max_son=siz[j],son[x]=j;
    }
}
void dfs2(int x,int topf){
    id[x]=++cnt,w2[cnt]=w[x],top[x]=topf;
    if(!son[x])return;
    dfs2(son[x],topf);
    for(int i=h[x];~i;i=ne[i]){
        int j=e[i];if(j==son[x]||j==fa[x])continue;
        dfs2(j,j);
    }
}
void push_down(int p){
    if(!seg[p].lazy)return;
    int l=seg[p].l,r=seg[p].r,mid=l+r>>1;
    seg[p<<1].lazy+=seg[p].lazy,seg[p<<1].sum+=seg[p].lazy*(mid-l+1);
    seg[p<<1|1].lazy+=seg[p].lazy,seg[p<<1|1].sum+=seg[p].lazy*(r-mid);
    seg[p].lazy=0;
}
void build(int p,int L,int R){
    seg[p].l=L,seg[p].r=R;
    if(L==R){seg[p].sum=w2[L]%mod;return;}
    int mid=L+R>>1;
    build(p<<1,L,mid);build(p<<1|1,mid+1,R);
    seg[p].sum=(seg[p<<1].sum+seg[p<<1|1].sum)%mod;
}
int query(int p,int L,int R){
    int l=seg[p].l,r=seg[p].r,mid=l+r>>1;
    if(L<=l&&r<=R)return seg[p].sum;
    int ans=0;push_down(p);
    if(L<=mid)ans+=query(p<<1,L,R);
    if(mid+1<=R)ans+=query(p<<1|1,L,R);
    return ans%mod;
}
void change(int p,int L,int R,int d){
    int l=seg[p].l,r=seg[p].r,mid=l+r>>1;
    if(L<=l&&r<=R){seg[p].sum+=d*(r-l+1);seg[p].lazy+=d;return;}
    push_down(p);
    if(L<=mid)change(p<<1,L,R,d);
    if(mid+1<=R)change(p<<1|1,L,R,d);
    seg[p].sum=(seg[p<<1].sum+seg[p<<1|1].sum)%mod;
}
int q_range(int x,int y){
    int ans=0;
    while(top[x]!=top[y]){
        if(deep[top[x]]deep[y])swap(x,y);
    ans+=query(1,id[x],id[y]);
    return ans;
}
void add_range(int x,int y,int d){
     while(top[x]!=top[y]){
        if(deep[top[x]]deep[y])swap(x,y);
     change(1,id[x],id[y],d);
}
int main()
{
    scanf("%d%d%d%d",&n,&m,&root,&mod);
    for(int i=1;i<=n;i++)scanf("%d",&w[i]);
    memset(h,-1,sizeof h);int a,b,op,z;
    for(int i=1;i

你可能感兴趣的:(图论,数据结构)