首页 > 代码库 > [BZOJ1036/ZJOI2008]树的统计(Count)-树链剖分

[BZOJ1036/ZJOI2008]树的统计(Count)-树链剖分

Problem 树的统计

题目大意

一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w。我们将以下面的形式来要求你对这棵树完成
一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值 I
II. QSUM u v: 询问从点u到点v的路径上的节点的权值和 注意:从点u到点v的路径上的节点包括u和v本身

So Lazy No Solution

裸的树链剖分,题解一搜一大把。就连这个都炸了几次。我太菜了。。。

AC Code

#include <iostream>
#include <cstdio>
#include <cstring>
#include <climits>
#define lc now<<1
using namespace std;
struct SGTree{
    int val,sum,mx;
}tr[120010];
struct Node{
    int to,next;
}a[60010];
int tot=0,dtot=0,x,n,m,h[30010],dep[30010],up[30010],size[30010];
int dfn[30010],rk[30010],fa[30010],val[30010],son[30010];
char tsk[10];
int dfs_sz(int now,int father,int depth){
    dep[now]=depth;
    fa[now]=father;
    int maxs=0,maxn=0;
    for(int i=h[now];~i;i=a[i].next)
        if(a[i].to!=father)
            size[now]+=dfs_sz(a[i].to,now,depth+1),
            maxs=max(size[a[i].to],maxs),
            maxn=(maxs==size[a[i].to])?a[i].to:maxn;
    son[now]=(maxn==0)?-1:maxn;
    size[now]++;
    return size[now];
}
void dfs_son(int now,int upest){
    dfn[now]=++dtot;
    rk[dtot]=now;
    up[now]=upest;
    if(son[now]==-1)return;
    dfs_son(son[now],upest);
    for(int i=h[now];~i;i=a[i].next)
        if(a[i].to!=fa[now]&&a[i].to!=son[now])
            dfs_son(a[i].to,a[i].to);
}
void add(int u,int v){
    a[++tot].to=v;a[tot].next=h[u];h[u]=tot;
    a[++tot].to=u;a[tot].next=h[v];h[v]=tot;
}
void build(int l,int r,int now){
    if(l==r){
        tr[now].mx=tr[now].val=tr[now].sum=val[rk[l]];
        return;
    }
    int mid=(l+r)>>1;
    tr[lc].mx=-INT_MAX,tr[(lc)+1].mx=-INT_MAX;
    build(l,mid,lc);
    build(mid+1,r,(lc)+1);
    tr[now].mx=max(tr[lc].mx,tr[(lc)+1].mx);
    tr[now].sum=tr[lc].sum+tr[(lc)+1].sum;
}
int sgt_max(int s,int t,int l,int r,int now){
    if(l==s&&r==t)return tr[now].mx;
    int mid=(l+r)>>1;
    if(t<=mid)return sgt_max(s,t,l,mid,lc);
    else if(mid<s)return sgt_max(s,t,mid+1,r,(lc)+1);
    else return max(sgt_max(s,mid,l,mid,lc),sgt_max(mid+1,t,mid+1,r,(lc)+1)); 
}
int sgt_sum(int s,int t,int l,int r,int now){
    if(l==s&&r==t)return tr[now].sum;
    int mid=(l+r)>>1;
    if(t<=mid)return sgt_sum(s,t,l,mid,lc);
    else if(mid<s)return sgt_sum(s,t,mid+1,r,(lc)+1);
    else return sgt_sum(s,mid,l,mid,lc)+sgt_sum(mid+1,t,mid+1,r,(lc)+1); 
}
int query_max(int s,int t){
    int u=up[s],v=up[t],ret=-INT_MAX;
    while(u!=v){
        if(dep[u]<dep[v])swap(u,v),swap(s,t);
        ret=max(ret,sgt_max(dfn[u],dfn[s],1,dtot,1));
        s=fa[u];
        u=up[s];
    }
    if(dep[s]>dep[t])swap(s,t);
    ret=max(ret,sgt_max(dfn[s],dfn[t],1,dtot,1));
    return ret;
}
int query_sum(int s,int t){
    int u=up[s],v=up[t],ret=0;
    while(u!=v){
        if(dep[u]<dep[v])swap(u,v),swap(s,t);
        ret+=sgt_sum(dfn[u],dfn[s],1,dtot,1);
        s=fa[u];
        u=up[s];
    }
    if(dep[s]>dep[t])swap(s,t);
    ret+=sgt_sum(dfn[s],dfn[t],1,dtot,1);
    return ret;
}
void change(int u,int x,int l,int r,int now){
    if(l==r&&l==u){
        tr[now].val=tr[now].mx=tr[now].sum=x;
        return;
    }
    int mid=(l+r)>>1;
    if(u<=mid)change(u,x,l,mid,lc);
    else change(u,x,mid+1,r,(lc)+1);
    tr[now].mx=max(tr[lc].mx,tr[(lc)+1].mx);
    tr[now].sum=tr[lc].sum+tr[(lc)+1].sum;}
int main(){
//  freopen("bzoj1036.in","r",stdin);
    memset(h,-1,sizeof(h));
    int u,v;
    scanf("%d",&n);
    for(int i=1;i<n;i++)
        scanf("%d%d",&u,&v),
        add(u,v);
    dfs_sz(1,0,0);
    dfs_son(1,1);
    for(int i=1;i<=n;i++)
        scanf("%d",&val[i]);
    build(1,dtot,1);
    scanf("%d",&m);
    for(int i=1;i<=m;i++){
        scanf("%s",tsk);
        if(tsk[0]==Q&&tsk[1]==M)
            scanf("%d%d",&u,&v),
            printf("%d\n",query_max(u,v));
        else if(tsk[0]==Q&&tsk[1]==S)
            scanf("%d%d",&u,&v),
            printf("%d\n",query_sum(u,v));
        else if(tsk[0]==C)
            scanf("%d%d",&u,&x),
            change(dfn[u],x,1,dtot,1);
    }
}

 

[BZOJ1036/ZJOI2008]树的统计(Count)-树链剖分