树链剖分

bzoj3924YES
bzoj4034YES
bzoj1576YES
bzoj3626YES神转化
bzoj2325
bzoj3589
bzoj4538
bzoj2908
bzoj3694YES
bzoj1146二分+树链剖分+线段树套平衡树
bzoj3531YES
bzoj1984YES
bzoj2243YES
bzoj4196YES
bzoj1036YES
poj3237YES

//bzoj3531
#include<cstdio>
#include<cstring>
#include<algorithm>

using namespace std;
const int N=131072;
const int inf=21333333;
int dep[N],sz[N],top[N],fa[N],pos[N],h[N];
int mx[N*100],sum[N*100],root[N*100],ls[N*100],rs[N*100];
int n,m,tot,x,y,z,w[N],c[N],tm,size;
struct edge{int y,next;}g[N*2];
char s[10];

void adp(int x,int y){
    g[++tot].y=y;
    g[tot].next=h[x];
    h[x]=tot;
}

void dfs1(int x){
    sz[x]=1;
    for (int i=h[x];i;i=g[i].next)
    if (g[i].y!=fa[x]){
        fa[g[i].y]=x;
        dep[g[i].y]=dep[x]+1;
        dfs1(g[i].y);
        sz[x]+=sz[g[i].y];
    }
}

void dfs2(int x,int t){
    top[x]=t;pos[x]=++tm;
    int son=0;
    for (int i=h[x];i;i=g[i].next)
    if (g[i].y!=fa[x] && sz[son]<sz[g[i].y])
        son=g[i].y;
    if (son) dfs2(son,t);
    for (int i=h[x];i;i=g[i].next)
    if (g[i].y!=fa[x] && g[i].y!=son)
        dfs2(g[i].y,g[i].y);
}

int lca(int x,int y){
    while (top[x]!=top[y]){
        if (dep[top[x]]>dep[top[y]])
            x=fa[top[x]]; else
            y=fa[top[y]];
    }
    if (dep[x]<dep[y])
        return x;
    return y;
}

void pushup(int rt){
    sum[rt]=sum[ls[rt]]+sum[rs[rt]];
    mx[rt]=max(mx[ls[rt]],mx[rs[rt]]);
}

void change(int &rt,int l,int r,int k,int val){
    if (!rt) rt=++size;
    if (l==r){mx[rt]=sum[rt]=val;return;}
    int mid=(l+r)>>1;
    if (k<=mid)
        change(ls[rt],l,mid,k,val); else
        change(rs[rt],mid+1,r,k,val);
    pushup(rt);
}

int querymax(int rt,int l,int r,int ll,int rr){
    if (!rt) return 0;
    if (l==ll && rr==r) return mx[rt];
    int mid=(l+r)>>1;int res=-inf;
    if (ll<=mid) res=max(res,querymax(ls[rt],l,mid,ll,min(mid,rr)));
    if (rr> mid) res=max(res,querymax(rs[rt],mid+1,r,max(mid+1,ll),rr));
    return res;
}

int querysum(int rt,int l,int r,int ll,int rr){
    if (!rt) return 0;
    if (l==ll && rr==r) return sum[rt];
    int mid=(l+r)>>1;int res=0;
    if (ll<=mid) res+=querysum(ls[rt],l,mid,ll,min(mid,rr));
    if (rr> mid) res+=querysum(rs[rt],mid+1,r,max(mid+1,ll),rr);
    return res;
}

int querysum(int cc,int x,int f){
    int res=0;
    while (top[x]!=top[f]){
        res+=querysum(root[cc],1,n,pos[top[x]],pos[x]);
        x=fa[top[x]];
    }
    res+=querysum(root[cc],1,n,pos[f],pos[x]);
    return res;
}

int querymax(int cc,int x,int f){
    int res=-inf;
    while (top[x]!=top[f]){
        res=max(res,querymax(root[cc],1,n,pos[top[x]],pos[x]));
        x=fa[top[x]];
    }
    res=max(res,querymax(root[cc],1,n,pos[f],pos[x]));
    return res;
}

int main(){
    scanf("%d%d",&n,&m);
    for (int i=1;i<=n;i++)
        scanf("%d%d",w+i,c+i);
    for (int i=1;i<n;i++){
        scanf("%d%d",&x,&y);
        adp(x,y);adp(y,x);
    }
    dfs1(1);dfs2(1,1);
    for (int i=1;i<=n;i++)
        change(root[c[i]],1,n,pos[i],w[i]);
    while (m--){
        scanf("%s",s);
        if (s[0]=='Q'){
            scanf("%d%d",&x,&y);
            int f=lca(x,y);
            if (s[1]=='S')
                printf("%d\n",querysum(c[x],x,f)+querysum(c[x],y,f)-(c[x]==c[f])*w[f]); else
                printf("%d\n",max(querymax(c[x],x,f),querymax(c[x],y,f)));
        } else {
            scanf("%d%d",&x,&z);
            if (s[1]=='C'){
                change(root[c[x]],1,n,pos[x],0);
                c[x]=z;
                change(root[c[x]],1,n,pos[x],w[x]);
            } else change(root[c[x]],1,n,pos[x],z),w[x]=z;
        }
    }
}

应用

将树上路径转化为序列用线段树维护。
将某棵子树(dfs序)询问转化为序列用线段树维护。
支持单点修改,路径修改,子树修改。
支持路径求和….
注意:树的形态不能变。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值