HYSBZ 1036 树链剖分(单点更新区间求和求最大值)

http://www.lydsy.com/JudgeOnline/problem.php?id=1036

Description

一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w。我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值 III. 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

/**
HYSBZ 1036 树链剖分(单点更新区间求和求最大值)
*/
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <iostream>
using namespace std;
const int maxn=30005;
int fa[maxn],dep[maxn],siz[maxn],son[maxn],top[maxn],num[maxn];
int n,q,z,a[maxn],Hash[maxn];
int tree[maxn*4],maxx[maxn*4];
int head[maxn],ip;

void init()
{
    memset(head,-1,sizeof(head));
    ip=0;
}

struct note
{
    int v,next;
} edge[maxn*2];

void addedge(int u,int v)
{
    edge[ip].v=v,edge[ip].next=head[u],head[u]=ip++;
}

void dfs(int u,int pre)
{
    fa[u]=pre,siz[u]=1,dep[u]=dep[pre]+1;
    for(int i=head[u]; i!=-1; i=edge[i].next)
    {
        int v=edge[i].v;
        if(v==pre)continue;
        dfs(v,u);
        siz[u]+=siz[v];
        if(siz[son[u]]<siz[v])
        {
            son[u]=v;
        }
    }
    //printf("%d siz fa dep son %d %d %d %d\n",u,siz[u],fa[u],dep[u],son[u]);
}

void init_que(int u,int tp)
{
    num[u]=++z,top[u]=tp,Hash[z]=u;
    if(son[u])
    {
        init_que(son[u],tp);
    }
    for(int i=head[u]; i!=-1; i=edge[i].next)
    {
        int v=edge[i].v;
        if(v==son[u]||v==fa[u])continue;
        init_que(v,v);
    }
    ///printf("%d top num %d %d\n",u,top[u],num[u]);
}

void push_up(int root)
{
    tree[root]=tree[root<<1]+tree[root<<1|1];
    maxx[root]=max(maxx[root<<1],maxx[root<<1|1]);
}
void build(int root,int l,int r)
{
    maxx[root]=-0x3f3f3f3f;
    tree[root]=0;
    if(l==r)
    {
        maxx[root]=tree[root]=a[Hash[l]];
        return;
    }
    int mid=(l+r)>>1;
    build(root<<1,l,mid);
    build(root<<1|1,mid+1,r);
    push_up(root);
}

void update(int root,int l,int r,int loc,int z)
{
    if(l>loc||r<loc)return;
    if(l==r)
    {
        maxx[root]=tree[root]=z;
        return;
    }
    int mid=(l+r)>>1;
    update(root<<1,l,mid,loc,z);
    update(root<<1|1,mid+1,r,loc,z);
    push_up(root);
}

int query(int root,int l,int r,int x,int y)
{
    if(l>y||r<x)return 0;
    if(x<=l&&r<=y)
    {
        return tree[root];
    }
    int mid=(l+r)>>1;
    return query(root<<1,l,mid,x,y)+query(root<<1|1,mid+1,r,x,y);
}
int query1(int root,int l,int r,int x,int y)
{
    if(l>y||r<x)return -0x3f3f3f3f;
    if(x<=l&&r<=y)
    {
        return maxx[root];
    }
    int mid=(l+r)>>1;
    return max(query1(root<<1,l,mid,x,y),query1(root<<1|1,mid+1,r,x,y));
}
int main()
{
    //freopen("data.txt","r",stdin);
    while(~scanf("%d",&n))
    {
        init();
        for(int i=1; i<n; i++)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            addedge(x,y);
            addedge(y,x);
        }
        for(int i=1; i<=n; i++)
        {
            scanf("%d",&a[i]);
        }
        int root=(n+1)>>1;
        z=0,dep[0]=0,siz[0]=0;
        dfs(root,0);
        init_que(root,root);
        build(1,1,z);
        scanf("%d",&q);
        while(q--)
        {
            char s[15];
            int x,y;
            scanf("%s%d%d",s,&x,&y);
            if(s[1]=='H')
            {
                update(1,1,z,num[x],y);
            }
            else if(s[1]=='S')
            {
                int f1=top[x],f2=top[y],sum=0;
                while(f1!=f2)
                {
                    if(dep[f1]<dep[f2])
                    {
                        swap(f1,f2);
                        swap(x,y);
                    }
                    sum+=query(1,1,z,num[f1],num[x]);
                    x=fa[f1],f1=top[x];
                }
                if(dep[x]>dep[y])
                {
                    swap(x,y);
                }
                sum+=query(1,1,z,num[x],num[y]);
                printf("%d\n",sum);
            }
            else
            {
                int f1=top[x],f2=top[y],sum=-0x3f3f3f3f;
                while(f1!=f2)
                {
                    if(dep[f1]<dep[f2])
                    {
                        swap(f1,f2);
                        swap(x,y);
                    }
                    sum=max(sum,query1(1,1,z,num[f1],num[x]));
                    x=fa[f1],f1=top[x];
                }
                if(dep[x]>dep[y])
                {
                    swap(x,y);
                }
                sum=max(sum,query1(1,1,z,num[x],num[y]));
                printf("%d\n",sum);
            }
        }
    }
    return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值