• 树链剖分记牢模板(含边 权)+例题


    这是对点权计算的板子

    #include<bits/stdc++.h>
    using namespace std;
    #define lson root<<1,l,midd
    #define rson root<<1|1,midd+1,r
    #define pb push_back
    typedef long long ll;
    inline int read(){
        int sum=0,x=1;
        char ch=getchar();
        while(ch<'0'||ch>'9'){
            if(ch=='-')
                x=0;
            ch=getchar();
        }
        while(ch>='0'&&ch<='9')
            sum=(sum<<1)+(sum<<3)+(ch^48),ch=getchar();
        return x?sum:-sum;
    }
    inline void write(int x){
        if(x<0)
            putchar('-'),x=-x;
        if(x>9)
            write(x/10);
        putchar(x%10+'0');
    }
    const int M=1e5+5;
    int fa[M],son[M],top[M],dfn[M],deep[M],to[M],sz[M],cnt;
    ll a[M],tree[M<<2],lazy[M<<2];
    vector<int>g[M];
    void dfs1(int u, int o) {
        fa[u] = o;
        sz[u] = 1;
        deep[u] = deep[o] + 1;
        for (int i = 0; i < g[u].size(); ++i) {
            int v = g[u][i];
            if(v != o) {
                dfs1(v, u);
                sz[u] += sz[v];
                if(sz[v] > sz[son[u]]) son[u] = v;
            }
        }
    }
    void dfs2(int u, int t) {
        top[u] = t;
        dfn[u] = ++cnt;
        to[cnt] = u;
        if(!son[u]) return ;
        dfs2(son[u], t);
        for (int i = 0; i < g[u].size(); ++i) {
            int v = g[u][i];
            if(v != fa[u] && v != son[u]) dfs2(v, v);
        }
    }
    int mod,n,m,reroot;
    void up(int root){
        tree[root]=tree[root<<1]+tree[root<<1|1];
        tree[root]%=mod;
    }
    void build(int root,int l,int r){
        if(l==r){
            tree[root]=a[to[l]];
            return ;
        }
        int midd=(l+r)>>1;
        build(lson);
        build(rson);
        up(root);
    }
    void pushdown(int root,int len){
        tree[root<<1]=(tree[root<<1]+lazy[root]*(len-(len>>1)))%mod;
        lazy[root<<1]=(lazy[root<<1]+lazy[root])%mod;
        tree[root<<1|1]=(tree[root<<1|1]+lazy[root]*(len>>1))%mod;
        lazy[root<<1|1]=(lazy[root<<1|1]+lazy[root])%mod;
        lazy[root]=0;
    }
    void update(int L,int R,ll w,int root,int l,int r){
        if(L<=l&&r<=R){
            tree[root]+=w*(r-l+1);
            tree[root]%=mod;
            lazy[root]+=w;
            lazy[root]%=mod;
            return ;
        }
        if(lazy[root])
            pushdown(root,r-l+1);
        int midd=(l+r)>>1;
        if(L<=midd)
            update(L,R,w,lson);
        if(R>midd)
            update(L,R,w,rson);
        up(root);
        return ;
    }
    void updates(int u,int v,int w){
        while(top[u]!=top[v]){
            if(deep[top[u]]<deep[top[v]])
                swap(u,v);
            update(dfn[top[u]],dfn[u],w,1,1,n);
            u=fa[top[u]];
        }
        if(deep[u]<deep[v])
            swap(u,v);
        update(dfn[v],dfn[u],w,1,1,n);
    }
    ll query(int L,int R,int root,int l,int r){
        if(L<=l&&r<=R){
            return tree[root];
        }
        if(lazy[root])
            pushdown(root,r-l+1);
        int midd=(l+r)>>1;
        ll ans=0;
        if(L<=midd)
            ans+=query(L,R,lson),ans%=mod;
        if(R>midd)
            ans+=query(L,R,rson),ans%=mod;
        return ans;
    }
    ll sum(int u,int v){
        ll ans=0;
        while(top[u]!=top[v]){
            if(deep[top[u]]<deep[top[v]])
                swap(u,v);
            ans+=query(dfn[top[u]],dfn[u],1,1,n);
            u=fa[top[u]];
        }
        if(deep[u]<deep[v])
            swap(u,v);
        ans+=query(dfn[v],dfn[u],1,1,n);
        return ans;
    }
    int main(){
        scanf("%d%d%d%d",&n,&m,&reroot,&mod);
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]);
        for(int i=1;i<n;i++){
            int u,v;
            scanf("%d%d",&u,&v);
            g[u].pb(v);
            g[v].pb(u);
        }
        dfs1(reroot,reroot);
        dfs2(reroot,reroot);
       // cout<<"!!"<<endl;
        build(1,1,n);
        while(m--){
            int op;
            scanf("%d",&op);
            if(op==1){
                int x,y;
                ll z;
                scanf("%d%d%lld",&x,&y,&z);
                updates(x,y,z);
            }
            else if(op==2){
                int x,y;
                scanf("%d%d",&x,&y);
                printf("%lld
    ",sum(x,y));
            }
            else if(op==3){
                int x;
                ll y;
                scanf("%d%lld",&x,&y);
    
                update(dfn[x],dfn[x]+sz[x]-1,y,1,1,n);
                //cout<<dfn[x]<<"!!"<<sz[x];
            }
            else{
                int x;
                scanf("%d",&x);
                printf("%lld
    ",query(dfn[x],dfn[x]+sz[x]-1,1,1,n));
            }
    
        }return 0;
    }
    

      

    下面是对于计算边权的板子的例题:(题目大意是:对于P :u,v表示u到v之间的边+1。对于Q:u,v表示输出u到v之间边之和;)

    千万注意俩者在add和solve函数部分的区别!!!!!!!!!!!!!!!

    https://vjudge.net/problem/SPOJ-GRASSPLA

    #include<iostream>
    #include<cstring>
    #include<vector>
    #include<algorithm>
    #include<vector>
    using namespace std;
    typedef long long ll;
    const int M=1e5+5;
    vector<int>g[M];
    int fa[M],son[M],sz[M],dfn[M],top[M],deep[M];
    ll tree[M<<2],lazy[M<<2];
    int cnt,n;
    void dfs1(int u,int from){
        fa[u]=from;
        sz[u]=1;
        deep[u]=deep[from]+1;
        for(int i=0;i<g[u].size();i++){
            int v=g[u][i];
            if(v!=from){
                dfs1(v,u);
                sz[u]+=sz[v];
                if(sz[v]>sz[son[u]])
                    son[u]=v;
            }
        }
    }
    void dfs2(int u,int t){
        top[u]=t;
        dfn[u]=++cnt;
        if(!son[u])
            return;
        dfs2(son[u],t);
        for(int i=0;i<g[u].size();i++){
            int v=g[u][i];
            if(v!=fa[u]&&v!=son[u])
                dfs2(v,v);
        }
    }
    void pushdown(int root,int len){
        int sign=lazy[root];
        lazy[root<<1]+=sign;
        lazy[root<<1|1]+=sign;
        tree[root<<1]+=(len-(len>>1))*1ll*sign;
        tree[root<<1|1]+=(len>>1)*1ll*sign;
        lazy[root]=0;
    }
    void update(int L,int R,int x,int root,int l,int r){
        if(L<=l&&r<=R){
            tree[root]+=x*(r-l+1)*1ll;
            lazy[root]+=x;
            return ;
        }
        if(lazy[root])
            pushdown(root,r-l+1);
        int midd=(l+r)>>1;
        if(L<=midd)
            update(L,R,x,root<<1,l,midd);
        if(R>midd)
            update(L,R,x,root<<1|1,midd+1,r);
        tree[root]=tree[root<<1]+tree[root<<1|1];
    }
    void add(int v,int u,int x){
        while(top[u]!=top[v]){
            if(deep[top[u]]<deep[top[v]])
                swap(u,v);
            update(dfn[top[u]],dfn[u],w,1,1,n);
            u=fa[top[u]];
        }
        if(deep[u]<deep[v])
            swap(u,v);
        update(dfn[v]+1,dfn[u],w,1,1,n);
         
    }
    ll query(int L,int R,int root,int l,int r){
        if(L<=l&&r<=R)
            return tree[root];
        ll ans=0;
        int midd=l+r>>1;
        if(lazy[root])
            pushdown(root,r-l+1);
        if(L<=midd)
            ans+=query(L,R,root<<1,l,midd);
        if(R>midd)
            ans+=query(L,R,root<<1|1,midd+1,r);
        tree[root]=tree[root<<1]+tree[root<<1|1];
        return ans;
    }
    ll solve(int v,int u){
        ll ans=0;
        while(top[u]!=top[v]){
            if(deep[top[u]]<deep[top[v]])
                swap(u,v);
            ans+=query(dfn[top[u]],dfn[u],1,1,n);
            u=fa[top[u]];
        }
        if(deep[u]<deep[v])
            swap(u,v);
        ans+=query(dfn[v]+1,dfn[u],1,1,n);
        return ans;
    }
    int main(){
        int m;
        scanf("%d%d",&n,&m);
        for(int i=1;i<n;i++){
            int x,y;
            scanf("%d%d",&x,&y);
            g[x].push_back(y);
            g[y].push_back(x);
        }
        dfs1(1,1);
        dfs2(1,1);
        /*for(int i=1;i<=n;i++)
            cout<<dfn[i]<<"~";
        cout<<endl;*/
        while(m--){
            char s[2];
            int x,y;
            scanf("%s%d%d",s,&x,&y);
             
            if(s[0]=='P')
                add(x,y,1);
            else
                printf("%lld
    ",solve(x,y));//
        }
        return 0;
    }
    View Code

     加换根操作的题

    描述
    给定一棵 n 个节点的树,初始时该树的根为 1 号节点,每个节点有一个给定的权值。下面依次进行 m 个操作,操作分为如下五种类型:

    换根:将一个指定的节点设置为树的新根。

    修改路径权值:给定两个节点,将这两个节点间路径上的所有节点权值(含这两个节点)增加一个给定的值。

    修改子树权值:给定一个节点,将以该节点为根的子树内的所有节点权值增加一个给定的值。

    询问路径:询问某条路径上节点的权值和。

    询问子树:询问某个子树内节点的权值和。

    输入
    第一行为一个整数 n,表示节点的个数。
    第二行 n 个整数表示第i个节点的初始权值 ai
    第三行 n−1 个整数,表示i+1 号节点的父节点编号 fi+1 (1⩽fi+1⩽n)
    第四行一个整数 m,表示操作个数。
    接下来 m 行,每行第一个整数表示操作类型编号:(1⩽u,v⩽n)
    若类型为 1,则接下来一个整数 u,表示新根的编号。
    若类型为 2,则接下来三个整数 u,v,k,分别表示路径两端的节点编号以及增加的权值。
    若类型为3,则接下来两个整数 u,k,分别表示子树根节点编号以及增加的权值。
    若类型为 4,则接下来两个整数u,v,表示路径两端的节点编号。
    若类型为 5,则接下来一个整数 u,表示子树根节点编号。

    输出
    对于每一个类型为 4 或 5 的操作,输出一行一个整数表示答案。

    样例输入
    6
    1 2 3 4 5 6
    1 2 1 4 4
    6
    4 5 6
    2 2 4 1
    5 1
    1 4
    3 1 2
    4 2 5

    样例输出
    15
    24
    19


    换根:对于路径查询、路径修改无影响,但对子树的从属,查询之类的有影响

    考虑root为当前的根,u为所求子树的根,lca为原图中的lca
    1.u==root,那么u 的子树就是整棵树。
    2.LCA(root,u)≠u,即root不在u的子树中。那么u现在的子树就是原来的子树
    3.LCA(root,u)=u,即u 在原来的树中是root 的祖先。那么我们找到u 到root 路径上的第一个儿子。这个儿子对应的原树中的子树,就是现在u 的子树的补集。

    #include<bits/stdc++.h>
    using namespace std;
    #define lson root<<1,l,midd
    #define rson root<<1|1,midd+1,r
    #define pb push_back
    typedef long long ll;
    const int M=1e5+5;
    ll tree[M<<2],lazy[M<<2],a[M];
    int dfn[M],sz[M],fa[M],son[M],deep[M],top[M],cnt,to[M];
    vector<int>g[M];
    inline int read(){
        int sum=0,x=1;
        char ch=getchar();
        while(ch<'0'||ch>'9'){
            if(ch=='-')
                x=0;
            ch=getchar();
        }
        while(ch>='0'&&ch<='9')
            sum=(sum<<1)+(sum<<3)+(ch^48),ch=getchar();
        return x?sum:-sum;
    }
    inline void write(int x){
        if(x<0)
            putchar('-'),x=-x;
        if(x>9)
            write(x/10);
        putchar(x%10+'0');
    }
    
    void dfs1(int u, int o) {
        fa[u] = o;
        sz[u] = 1;
        deep[u] = deep[o] + 1;
        for (int i = 0; i < g[u].size(); ++i) {
            int v = g[u][i];
            if(v != o) {
                dfs1(v, u);
                sz[u] += sz[v];
                if(sz[v] > sz[son[u]]) son[u] = v;
            }
        }
    }
    void dfs2(int u, int t) {
        top[u] = t;
        dfn[u] = ++cnt;
        to[cnt] = u;
        if(!son[u]) return ;
        dfs2(son[u], t);
        for (int i = 0; i < g[u].size(); ++i) {
            int v = g[u][i];
            if(v != fa[u] && v != son[u]) dfs2(v, v);
        }
    }
    int n,reroot=1;
    void up(int root){
        tree[root]=tree[root<<1]+tree[root<<1|1];
        tree[root];
    }
    void build(int root,int l,int r){
        if(l==r){
            tree[root]=a[to[l]];
            return ;
        }
        int midd=(l+r)>>1;
        build(lson);
        build(rson);
        up(root);
    }
    void pushdown(int root,int len){
        tree[root<<1]=(tree[root<<1]+lazy[root]*(len-(len>>1)));
        lazy[root<<1]=(lazy[root<<1]+lazy[root]);
        tree[root<<1|1]=(tree[root<<1|1]+lazy[root]*(len>>1));
        lazy[root<<1|1]=(lazy[root<<1|1]+lazy[root]);
        lazy[root]=0;
    }
    void update(int L,int R,ll w,int root,int l,int r){
        if(L<=l&&r<=R){
            tree[root]+=w*(r-l+1);
            lazy[root]+=w;
            return ;
        }
        if(lazy[root])
            pushdown(root,r-l+1);
        int midd=(l+r)>>1;
        if(L<=midd)
            update(L,R,w,lson);
        if(R>midd)
            update(L,R,w,rson);
        up(root);
        return ;
    }
    void Update(int u,int v,int w){
        while(top[u]!=top[v]){
            if(deep[top[u]]<deep[top[v]])
                swap(u,v);
            update(dfn[top[u]],dfn[u],w,1,1,n);
            u=fa[top[u]];
        }
        if(deep[u]<deep[v])
            swap(u,v);
        update(dfn[v],dfn[u],w,1,1,n);
        
    }
    ll query(int L,int R,int root,int l,int r){
        if(L<=l&&r<=R){
            return tree[root];
        }
        if(lazy[root])
            pushdown(root,r-l+1);
        int midd=(l+r)>>1;
        ll ans=0;
        if(L<=midd)
            ans+=query(L,R,lson);
        if(R>midd)
            ans+=query(L,R,rson);
        return ans;
    }
    ll sum(int u,int v){
        ll ans=0;
        while(top[u]!=top[v]){
            if(deep[top[u]]<deep[top[v]])
                swap(u,v);
            ans+=query(dfn[top[u]],dfn[u],1,1,n);
            u=fa[top[u]];
        }
        if(deep[u]<deep[v])
            swap(u,v);
        ans+=query(dfn[v],dfn[u],1,1,n);
        return ans;
    }
    int find(int x,int y){ //找x到y的第一个儿子
        while(top[x]!=top[y]){
            if(deep[top[x]]<deep[top[y]]) swap(x,y);
            if(fa[top[x]]==y) return top[x];
            x=fa[top[x]];
        }
        if(deep[x]<deep[y]) swap(x,y);
        return son[y];
    }
    
    int LCA(int u,int v){
        while(top[u]!=top[v]){
            if(deep[top[u]]<deep[top[v]])
                swap(u,v);
            u=fa[top[u]];
        }
        return deep[u]>deep[v]?v:u;
    } 
    void Updatesub(int u,ll w){//操作3用到 
        if(u==reroot){
            update(1,n,w,1,1,n);
            return ;
        }
            
        int nearlca=LCA(u,reroot);
        if(nearlca!=u){
            update(dfn[u],dfn[u]+sz[u]-1,w,1,1,n);
            return ;
        }
        else{
            int nearchild=find(u,reroot);
            update(1,n,w,1,1,n);
            update(dfn[nearchild],dfn[nearchild]+sz[nearchild]-1,-w,1,1,n);
            return ;
        }
            
    }
    ll sumsub(int x){//操作5 
        if(x==reroot)
            return query(1,n,1,1,n);
        int nearlca=LCA(x,reroot);
        if(nearlca!=x)
            return query(dfn[x],dfn[x]+sz[x]-1,1,1,n);
        int nearch=find(x,reroot);
        ll ans=query(1,n,1,1,n);
        return ans-query(dfn[nearch],dfn[nearch]+sz[nearch]-1,1,1,n);
    }
    int main(){
        n=read();
        for(int i=1;i<=n;i++)
            a[i]=read();
        for(int i=2;i<=n;i++){
            int x;
            scanf("%d",&x);
            g[x].pb(i);
            g[i].pb(x);
        }
        dfs1(1,1);
        dfs2(1,1);
        build(1,1,n);
        int m;
        m=read();
        while(m--){
            int op=read();
            if(op==1){
                int x=read();
                reroot=x;
            }
            else if(op==2){
                int u=read(),v=read();
                ll w=1ll*read();
                Update(u,v,w);
            }
            else if(op==3){
                int u=read();
                ll w=1ll*read();
                Updatesub(u,w);
            }
            else if(op==4){
                int  u=read(),v=read();
                printf("%lld
    ",sum(u,v));
            }
            else{
                int u=read();
                printf("%lld
    ",sumsub(u));
            }
        }
        return 0;
    }
    
    更新查找链换码风
    View Code

    题:https://codeforces.com/contest/343/problem/D

    #include<bits/stdc++.h>
    using namespace std;
    #define pb push_back
    #define lson root<<1,l,midd
    #define rson root<<1|1,midd+1,r
    const int M=5e5+5;
    int sz[M],deep[M],fa[M],dfn[M],top[M],son[M],tree[M<<2],lazy[M<<2],cnt,n;
    vector<int>g[M];
    void dfs1(int u,int f){
        sz[u]=1;
        deep[u]=deep[f]+1;
        fa[u]=f;
        for(auto v: g[u]){
            if(v!=f){
                dfs1(v,u);
                sz[u]+=sz[v];
                if(sz[v]>sz[son[u]])
                    son[u]=v;
            }
        }
    }
    void dfs2(int u,int t){
        top[u]=t;
        dfn[u]=++cnt;
       /// to[cnt]=u;
        if(!son[u])
            return ;
        dfs2(son[u],t);
        for(auto v:g[u]){
            if(v!=fa[u]&&v!=son[u])
                dfs2(v,v);
        }
    }
    void pushdown(int root){
        tree[root<<1]=tree[root<<1|1]=lazy[root];
        lazy[root<<1]=lazy[root<<1|1]=lazy[root];
        lazy[root]=-1;
    }
    void update(int L,int R,int w,int root,int l,int r){
        if(L<=l&&r<=R){
            tree[root]=w;
            lazy[root]=w;
            return ;
        }
        if(lazy[root]!=-1)
            pushdown(root);
        int midd=(l+r)>>1;
        if(L<=midd)
            update(L,R,w,lson);
        if(R>midd)
            update(L,R,w,rson);
    }
     
    int query(int pos,int root,int l,int r){
        if(l==r){
            return tree[root];
        }
        if(lazy[root]!=-1)
            pushdown(root);
        int midd=(l+r)>>1;
        if(pos<=midd)
            return query(pos,lson);
        if(pos>midd)
            return query(pos,rson);
    }
    void add(int u,int v,int w){
        while(top[u]!=top[v]){
            if(deep[top[u]]<deep[top[v]]){
                swap(u,v);
            }
            update(dfn[top[u]],dfn[u],w,1,1,n);
            u=fa[top[u]];
        }
        if(deep[u]<deep[v])
            swap(u,v);
        update(dfn[v],dfn[u],w,1,1,n);
    }
    int main(){
        memset(lazy,-1,sizeof(lazy));
        scanf("%d",&n);
        for(int u,v,i=1;i<n;i++){
            scanf("%d %d",&u,&v);
            g[u].pb(v);
            g[v].pb(u);
        }
        dfs1(1,1);
        dfs2(1,1);
        int m;
        scanf("%d",&m);
        while(m--){
            int op,x;
            scanf("%d%d",&op,&x);
            if(op==1){
                update(dfn[x],dfn[x]+sz[x]-1,1,1,1,n);
            }
            else if(op==2){
                add(1,x,0);
            }
            else{
                printf("%d
    ",query(dfn[x],1,1,n));
            }
        }
        return 0;
    }
    View Code

    洛谷:https://www.luogu.org/problem/P2486

    #include<bits/stdc++.h>
    using namespace std;
    const  int M=3e5+5;
    struct node{
        int l,r,cnt,lazy;
        node(int l1=0,int r1=0,int cnt1=0,int lazy1=0):l(l1),r(r1),cnt(cnt1),lazy(lazy1){}
    }tree[M<<2];
    int fa[M],sz[M],deep[M],dfn[M],son[M],to[M],a[M],top[M],cnt,n;
    char s[2];
    vector<int>g[M];
    void dfs1(int u,int from){
        fa[u]=from;
        sz[u]=1;
        deep[u]=deep[from]+1;
        for(int i=0;i<g[u].size();i++){
    
            int v=g[u][i];
            if(v!=from){
                dfs1(v,u);
                sz[u]+=sz[v];
                if(sz[v]>sz[son[u]])
                    son[u]=v;
            }
            
        }
    }
    void dfs2(int u,int t){
        top[u]=t;
        dfn[u]=++cnt;
        to[cnt]=u;
        if(!son[u])
            return ;
        dfs2(son[u],t);
        for(int i=0;i<g[u].size();i++){
            int v=g[u][i];
            if(v!=fa[u]&&v!=son[u])
                dfs2(v,v);
        }
    }
    void up(int root){
        tree[root].cnt=tree[root<<1].cnt+tree[root<<1|1].cnt;
        if(tree[root<<1].r==tree[root<<1|1].l)
            tree[root].cnt--;
        tree[root].l=tree[root<<1].l;
        tree[root].r=tree[root<<1|1].r;
    }
    void build(int root,int l,int r){
        tree[root].lazy=0;
        if(l==r){
            tree[root].l=tree[root].r=a[to[l]];
            tree[root].cnt=1;
            return ;
        }
        int midd=(l+r)>>1;
        build(root<<1,l,midd);
        build(root<<1|1,midd+1,r);
        up(root);
    }
    void pushdown(int root){
        tree[root<<1]=tree[root<<1|1]=node(tree[root].l,tree[root].r,1,tree[root].lazy);
        tree[root].lazy=0;
    }
    void update(int L,int R,int x,int root,int l,int r){
        if(L<=l&&r<=R){
            tree[root]=node(x,x,1,x);
            return ;
        }
        if(tree[root].lazy)
            pushdown(root);
        int midd=(l+r)>>1;
        if(L<=midd)
            update(L,R,x,root<<1,l,midd);
        if(R>midd)
            update(L,R,x,root<<1|1,midd+1,r);
        up(root);
    }
    void add(int u,int v ,int w){
        int fu=top[u],fv=top[v];
        while(fu!=fv){
            if(deep[fu]>=deep[fv])
                update(dfn[fu],dfn[u],w,1,1,n),u=fa[fu],fu=top[u];
            else
                update(dfn[fv],dfn[v],w,1,1,n),v=fa[fv],fv=top[v];
        }
        if(dfn[u]<=dfn[v])
            update(dfn[u],dfn[v],w,1,1,n);
        else
            update(dfn[v],dfn[u],w,1,1,n);
    }
    node meger(node a,node b){
        if(!a.cnt)
            return b;
        if(!b.cnt)
            return a;
        node ans=node(0,0,0,0);
        ans.cnt=a.cnt+b.cnt;
        if(a.r==b.l)
            ans.cnt--;
        ans.l=a.l;
        ans.r=b.r;
        return ans;
    }
    node query(int L,int R,int root,int l,int r){
        if(L<=l&&r<=R){
            return tree[root];
        }
        if(tree[root].lazy)
            pushdown(root);
        int midd=(l+r)>>1;
        node ans;
        if(L<=midd)
            ans=query(L,R,root<<1,l,midd);
        if(R>midd)
            ans=meger(ans,query(L,R,root<<1|1,midd+1,r));
        up(root);
        return ans;
    }
    int solve(int u,int v){
        node l,r;
        int fv=top[v],fu=top[u];
        while(fv!=fu){
            if(deep[fu]>=deep[fv])
                l=meger(query(dfn[fu],dfn[u],1,1,n),l),u=fa[fu],fu=top[u];
            else
                r=meger(query(dfn[fv],dfn[v],1,1,n),r),v=fa[fv],fv=top[v];
        }
        if(dfn[u]<=dfn[v])
            r=meger(query(dfn[u],dfn[v],1,1,n),r);
        else
            l=meger(query(dfn[v],dfn[u],1,1,n),l);
        swap(l.l,l.r);
        l=meger(l,r);//线段树是沿子树往下搜的,所以在合并的时候要保证同方向(因为这涉及到链的颜色排布问题,如果俩条链不同向可能会导致结果发生错误
        return l.cnt;
    }
    int main(){
        int m;
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]);
        for(int i=1;i<n;i++){
            int u,v;
            scanf("%d%d",&u,&v);
            g[u].push_back(v);
            g[v].push_back(u);
        }//cout<<"!!"<<endl;
        dfs1(1,1);
        dfs2(1,1);
        
        build(1,1,n);
        while(m--){
            int u,v,w;
            scanf("%s",s);
            if(s[0]=='Q'){
                scanf("%d%d",&u,&v);
                printf("%d
    ",solve(u,v));
            }
            else{
                scanf("%d%d%d",&u,&v,&w);
                add(u,v,w);
            }
        }
        return 0;
    }
    View Code

     题:https://www.luogu.org/problem/P4315

    #include<bits/stdc++.h>
    using namespace std;
    const int MAXN=1e5+10;
    const int MAXM=2e5+10;
    
    int n,m,cnt=1;
    int head[MAXN],depth[MAXN],siz[MAXN],son[MAXN],fa[MAXN],top[MAXN];
    int dfn[MAXN],ys[MAXN],tot;
    int a[MAXN];
    struct Tree{
        int l,r;
        int maxx,add;
        int cover;
    }tr[MAXN<<2];
    struct Edge{
        int nxt,to,w;
    }edge[MAXM];
    
    int Read(){
        int i=0,f=1;
        char c;
        for(c=getchar();(c>'9'||c<'0')&&c!='-';c=getchar());
        if(c=='-')
          f=-1,c=getchar();
        for(;c>='0'&&c<='9';c=getchar())
          i=(i<<3)+(i<<1)+c-'0';
        return i*f;
    }
    
    void add(int x,int y,int z){
        cnt++;
        edge[cnt].nxt=head[x];
        head[x]=cnt;
        edge[cnt].to=y;
        edge[cnt].w=z;
    }
    
    void dfs1(int u,int f){
        siz[u]=1;
        for(int i=head[u];i!=-1;i=edge[i].nxt){
            int v=edge[i].to;
            if(v==f)
              continue;
            a[v]=edge[i].w;
            depth[v]=depth[u]+1,fa[v]=u;
            dfs1(v,u);
            siz[u]+=siz[v];
            if(siz[v]>siz[son[u]])
              son[u]=v;
        }
    }
    
    void dfs2(int u,int tp){
        top[u]=tp;
        dfn[u]=++tot;
        ys[tot]=u;
        if(!son[u])
          return ;
        dfs2(son[u],tp);
        for(int i=head[u];i!=-1;i=edge[i].nxt){
            int v=edge[i].to;
            if(v==fa[u]||v==son[u])
              continue;
            dfs2(v,v);
        }
    }
    
    void push_up(int root){
        tr[root].maxx=max(tr[root<<1].maxx,tr[root<<1|1].maxx);
    }
    
    void push_cover(int root,int v){
        tr[root].cover=v;
        tr[root].add=0;
        tr[root].maxx=v;
    }
    
    void push_add(int root,int v){
        tr[root].add+=v;
        tr[root].maxx+=v;
    }
    
    void push_down(int root){
        if(tr[root].cover!=-1){
            push_cover(root<<1,tr[root].cover);
            push_cover(root<<1|1,tr[root].cover);
            tr[root].cover=-1;
        }
        if(tr[root].add){
            push_add(root<<1,tr[root].add);
            push_add(root<<1|1,tr[root].add);
            tr[root].add=0;
        }
    }
    
    void build(int root,int l,int r){
        tr[root].cover=-1;
        tr[root].l=l,tr[root].r=r;
        if(l==r){
            tr[root].maxx=a[ys[l]];
            return ;
        }
        int mid=l+r>>1;
        build(root<<1,l,mid);
        build(root<<1|1,mid+1,r);
        push_up(root);
    }
    
    void update_cover(int root,int l,int r,int L,int R,int key){
        if(l>R||r<L)
          return ;
        if(L<=l&&r<=R){
            push_cover(root,key);
            return ;
        }
        push_down(root);
        int mid=(l+r)>>1;
        if(R<=mid)
          update_cover(root<<1,l,mid,L,R,key);
        else{
            if(L>mid)
              update_cover(root<<1|1,mid+1,r,L,R,key);
            else
              update_cover(root<<1,l,mid,L,mid,key),update_cover(root<<1|1,mid+1,r,mid+1,R,key);
        }
        push_up(root);
    }
    
    void update_add(int root,int l,int r,int L,int R,int key){
        if(l>R||r<L)
          return ;
        if(L<=l&&r<=R){
            push_add(root,key);
            return ;
        }
        push_down(root);
        int mid=l+r>>1;
        if(R<=mid)
          update_add(root<<1,l,mid,L,R,key);
        else{
            if(L>mid)
              update_add(root<<1|1,mid+1,r,L,R,key);
            else
              update_add(root<<1,l,mid,L,mid,key),update_add(root<<1|1,mid+1,r,mid+1,R,key);
        }
        push_up(root);
    }
    
    int query(int root,int l,int r,int L,int R){
        if(l>R||r<L)
          return 0;
        if(L<=l&&r<=R)
          return tr[root].maxx;
        push_down(root);  
        int mid=l+r>>1;
        if(R<=mid)
          return query(root<<1,l,mid,L,R);
        else{
            if(L>mid)
              return query(root<<1|1,mid+1,r,L,R);
            else
              return max(query(root<<1,l,mid,L,mid),query(root<<1|1,mid+1,r,mid+1,R));
        }
    }
    
    void updatepath_cover(int x,int y,int key){
        while(top[x]!=top[y]){
            if(depth[top[x]]<depth[top[y]])
              swap(x,y);
            update_cover(1,1,n,dfn[top[x]],dfn[x],key);
            x=fa[top[x]];
        }
        if(depth[x]<depth[y])
          swap(x,y);
        update_cover(1,1,n,dfn[y]+1,dfn[x],key);
    }
    
    void updatepath_add(int x,int y,int key){
        while(top[x]!=top[y]){
            if(depth[top[x]]<depth[top[y]])
              swap(x,y);
            update_add(1,1,n,dfn[top[x]],dfn[x],key);
            x=fa[top[x]];
        }
        if(depth[x]<depth[y])
          swap(x,y);
        update_add(1,1,n,dfn[y]+1,dfn[x],key);
    }
    
    int querypath(int x,int y){
        int ret=0;
        while(top[x]!=top[y]){
            if(depth[top[x]]<depth[top[y]])
              swap(x,y);
            ret=max(ret,query(1,1,n,dfn[top[x]],dfn[x]));
            x=fa[top[x]];
        }
        if(depth[x]<depth[y])
          swap(x,y);
        ret=max(ret,query(1,1,n,dfn[y]+1,dfn[x]));
        return ret;
    }
    
    int find(int x){
        return depth[edge[x<<1].to]>depth[edge[x<<1^1].to]?edge[x<<1].to:edge[x<<1^1].to;
    }
    
    int main(){
        memset(head,-1,sizeof(head));
        scanf("%d",&n);
        for(int i=1;i<n;++i){
            int x,y,z;
            scanf("%d%d%d",&x,&y,&z);
            add(x,y,z),add(y,x,z);
        }
        dfs1(1,-1);
        dfs2(1,1);
        build(1,1,n);
        char cz[10];
        scanf("%s",cz);
        while(cz[0]!='S'){
            int x=Read(),y=Read();
            if(cz[1]=='h'){
                update_cover(1,1,n,dfn[find(x)],dfn[find(x)],y);
            }
            if(cz[1]=='o'){
                int k=Read();
                updatepath_cover(x,y,k);
            }
            if(cz[0]=='A'){
                int k=Read();
                updatepath_add(x,y,k);
            }
            if(cz[0]=='M')
                printf("%d
    ",querypath(x,y));
            scanf("%s",cz);
        }
        return 0;
    }
    View Code
     
  • 相关阅读:
    Android 走向MD的配色风格
    Android热点回顾第六期
    C#集合类:动态数组、队列、栈、哈希表、字典(转)
    Google Chrome默认字体设置(Win)
    C# Socket的粘包处理(转)
    设计模式原则总结--读《大话设计模式》有感 <转>
    C#设计模式学习笔记-单例模式(转)
    C# 编写Windows Service(windows服务程序)
    C# 获取农历日期
    C# 中怎么将string转换成int型
  • 原文地址:https://www.cnblogs.com/starve/p/11848103.html
Copyright © 2020-2023  润新知