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

这是对点权计算的板子

#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\n",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\n",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\n",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\n",sum(u,v));
        }
        else{
            int u=read();
            printf("%lld\n",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\n",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\n",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\n",querypath(x,y));
        scanf("%s",cz);
    }
    return 0;
}
View Code

 

 
posted @ 2019-11-13 12:49  starve_to_death  阅读(168)  评论(0编辑  收藏  举报