bzoj 1036 树链剖分

Posted LuZhiyuan

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj 1036 树链剖分相关的知识,希望对你有一定的参考价值。

1036: [ZJOI2008]树的统计Count

Time Limit: 10 Sec  Memory Limit: 162 MB
Submit: 18993  Solved: 7748
[Submit][Status][Discuss]

Description

  一棵树上有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本身

Input

  输入的第一行为一个整数n,表示节点的个数。接下来n – 1行,每行2个整数a和b,表示节点a和节点b之间有
一条边相连。接下来n行,每行一个整数,第i行的整数wi表示节点i的权值。接下来1行,为一个整数q,表示操作
的总数。接下来q行,每行一个操作,以“CHANGE u t”或者“QMAX u v”或者“QSUM u v”的形式给出。 
对于100%的数据,保证1<=n<=30000,0<=q<=200000;中途操作中保证每个节点的权值w在-30000到30000之间。

Output

  对于每个“QMAX”或者“QSUM”的操作,每行输出一个整数表示要求输出的结果。

Sample Input

4
1 2
2 3
4 1
4 2 1 3
12
QMAX 3 4
QMAX 3 3
QMAX 3 2
QMAX 2 3
QSUM 3 4
QSUM 2 1
CHANGE 1 5
QMAX 3 4
CHANGE 3 6
QMAX 3 4
QMAX 2 4
QSUM 3 4

Sample Output

4
1
2
2
10
6
5
6
5
16

HINT

 

Source

 代码:
//和上一题稍微不同,这题权值在点上。
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int MAXN=30000;
int fa[MAXN+9],son[MAXN+9],lev[MAXN+9],top[MAXN+9],id[MAXN+9],head[MAXN+9],size[MAXN+9],val[MAXN+9];
int max_[MAXN*4+9],sum_[MAXN*4+9],tot,cnt;
struct Edge
{
    int u,v,next;
}edge[MAXN*2+9];
void init()
{
    tot=cnt=0;
    for(int i=0;i<=MAXN;i++) fa[i]=top[i]=i;
    memset(sum_,0,sizeof(sum_));
    memset(head,-1,sizeof(head));
}
void add(int x,int y)
{
    edge[tot].u=x;edge[tot].v=y;
    edge[tot].next=head[x];
    head[x]=tot++;
    edge[tot].u=y;edge[tot].v=x;
    edge[tot].next=head[y];
    head[y]=tot++;
}
void dfs1(int x,int d)
{
    lev[x]=d;
    son[x]=0;
    size[x]=1;
    for(int i=head[x];i!=-1;i=edge[i].next){
        int y=edge[i].v;
        if(y==fa[x]) continue;
        fa[y]=x;
        dfs1(y,d+1);
        size[x]+=size[y];
        if(size[son[x]]<size[y]) son[x]=y;
    }
}
void dfs2(int x,int tp)
{
    top[x]=tp;
    id[x]=++cnt;
    if(son[x]) dfs2(son[x],tp);
    for(int i=head[x];i!=-1;i=edge[i].next){
        int y=edge[i].v;
        if(y==fa[x]||y==son[x]) continue;
        dfs2(y,y);
    }
}
void pushup(int rt)
{
    max_[rt]=max(max_[rt<<1],max_[rt<<1|1]);
    sum_[rt]=sum_[rt<<1]+sum_[rt<<1|1];
}
void build(int l,int r,int rt)
{
    if(l==r){
        max_[rt]=sum_[rt]=val[l];
        return;
    }
    int mid=(l+r)>>1;
    build(l,mid,rt<<1);
    build(mid+1,r,rt<<1|1);
    pushup(rt);
}
void update(int id,int c,int l,int r,int rt)
{
    if(l==r){
        max_[rt]=sum_[rt]=c;
        return;
    }
    int mid=(l+r)>>1;
    if(id<=mid) update(id,c,l,mid,rt<<1);
    else update(id,c,mid+1,r,rt<<1|1);
    pushup(rt);
}
int query1(int ql,int qr,int l,int r,int rt)
{
    if(ql<=l&&qr>=r) return max_[rt];
    int mid=(l+r)>>1,ans=-MAXN-9;
    if(ql<=mid) ans=max(ans,query1(ql,qr,l,mid,rt<<1));
    if(qr>mid) ans=max(ans,query1(ql,qr,mid+1,r,rt<<1|1));
    return ans;
}
int query2(int ql,int qr,int l,int r,int rt)
{
    if(ql<=l&&qr>=r) return sum_[rt];
    int mid=(l+r)>>1,ans=0;
    if(ql<=mid) ans+=query2(ql,qr,l,mid,rt<<1);
    if(qr>mid) ans+=query2(ql,qr,mid+1,r,rt<<1|1);
    return ans;
}
int solve(int l,int r,bool f)
{
    int ltp=top[l],rtp=top[r],ans=(f?0:-MAXN-9);
    while(ltp!=rtp){
        if(lev[rtp]<lev[ltp]){
            swap(ltp,rtp);
            swap(l,r);
        }
        if(!f) ans=max(ans,query1(id[rtp],id[r],1,cnt,1));
        else ans+=query2(id[rtp],id[r],1,cnt,1);
        r=fa[rtp];
        rtp=top[r];
    }
    if(lev[r]>lev[l]) swap(l,r);
    if(!f) ans=max(ans,query1(id[r],id[l],1,cnt,1));
    else ans+=query2(id[r],id[l],1,cnt,1);
    return ans;
}
int main()
{
    //freopen("in.txt","r",stdin);
    int n,q;
    scanf("%d",&n);
    init();
    for(int i=1;i<n;i++){
        int x,y;
        scanf("%d%d",&x,&y);
        add(x,y);
    }
    dfs1(1,1);
    dfs2(1,1);
    for(int i=1;i<=n;i++){
        int x;
        scanf("%d",&x);
        val[id[i]]=x;
    }
    build(1,cnt,1);
    scanf("%d",&q);
    char ch[10];
    while(q--){
        int x,y;
        scanf("%s%d%d",ch,&x,&y);
        if(ch[0]==C) update(id[x],y,1,cnt,1);
        else if(ch[1]==M) printf("%d\n",solve(x,y,0));
        else printf("%d\n",solve(x,y,1));
    }
    return 0;
}

 

以上是关于bzoj 1036 树链剖分的主要内容,如果未能解决你的问题,请参考以下文章

bzoj 1036 树链剖分

BZOJ 1036 树链剖分模板题

树链剖分学习&BZOJ1036

bzoj 1036: [ZJOI2008]树的统计Count (树链剖分)

BZOJ 1036ZJOI 2008树的统计 树链剖分模板题

bzoj 1036 [ZJOI2008]树的统计Count(树链剖分,线段树)