线段树

dfs序,对结点进行重编号,要达到的目的是使子树节点的编号都大于父节点,编号完毕后,
如果某个节点是非叶子节点,那么它子树节点中的最大值和这个节点的编号代表的区间代表这个子树。
编号同时,根节点到此节点(包括此节点)的节点权值和求出,令存数组中。
这个新处理出的数组和要求的查询和修改就是(模板的区间求最大值及修改)。过程自行思考。
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<iostream>
#include<cstdio>
#include<cstring>
#define lt (2*root)
#define rt (2*root+1)
#define inf 0x3f3f3f3f3f3f3f3f;
using namespace std;
typedef __int64 LL;
LL a[101000];
LL b[101000];
LL head[101000],p,book[101000];
LL max(LL x,LL y){return x>y?x:y;}
struct NOde
{
    LL Max,mark;
}v[401000];
struct Node
{
    int l,r;LL s;//本采用全LL的数据类型,但莫名错误了,求解释?(换下行会WR..)
    //LL l,r,s; 
}c[101000];
struct Edge
{
    LL u,v,next;
}edges[301000];
void build(LL root,LL l,LL r)
{
    if(l==r){v[root].Max=b[l],v[root].mark=0;return;}
    LL mid=(l+r)/2;
    build(lt,l,mid);
    build(rt,mid+1,r);
    v[root].Max=max(v[lt].Max,v[rt].Max);
    v[root].mark=0;
}
void done(LL root,LL value)
{
    v[root].Max=v[root].Max+value;
    v[lt].mark=v[lt].mark+value;
    v[rt].mark=v[rt].mark+value;
}
void push_down(LL root)
{
    if(v[root].mark)
    {
        v[root].Max=v[root].Max+v[root].mark;
        v[lt].mark=v[lt].mark+v[root].mark;
        v[rt].mark=v[rt].mark+v[root].mark;
        v[root].mark=0;
    }
}
void update(LL root,LL l,LL r,LL from,LL to,LL value)
{
    push_down(root);
    if(l>to||r<from) return;
    if(l>=from&&r<=to){done(root,value);return;}
    LL mid=(l+r)/2;
    update(lt,l,mid,from,to,value);
    update(rt,mid+1,r,from,to,value);
    v[root].Max=max(v[lt].Max,v[rt].Max);
}
LL query(LL root,LL l,LL r,LL from,LL to)
{
    push_down(root);
    if(l>to||r<from) return -inf;
    if(l>=from&&r<=to) return v[root].Max;
    LL mid=(l+r)/2;
    return max(query(lt,l,mid,from,to),query(rt,mid+1,r,from,to));
}
void addedges(LL u,LL v)
{
    edges[p].u=u;
    edges[p].v=v;
    edges[p].next=head[u];
    head[u]=p++;
}
LL id=1;
void dfs(LL st,LL sum)
{
    c[st].s=sum+a[st];
    book[st]=1;
    c[st].l=id;
    b[id]=sum+a[st];
    for(LL i=head[st];i!=-1;i=edges[i].next)
    {
        LL to=edges[i].v;
        if(book[to]) continue;
        id=id+1;
        dfs(to,sum+a[st]);
    }
    c[st].r=id;
    book[st]=0;
}
void init(LL n)
{
    id=1;
    dfs(0,0);
    build(1,1,n);
}
int main()
{
    //freopen("C:/Users/hzy/Desktop/12.txt","r",stdin);
    LL t,kcase=1;
    scanf("%I64d",&t);
    while(t--)
    {
        memset(head,-1,sizeof(head));
        p=0;
        LL n,m;
        scanf("%I64d%I64d",&n,&m);
        for(LL i=0;i<n-1;i++)
        {
            LL u,v;
            scanf("%I64d%I64d",&u,&v);
            addedges(u,v);
            addedges(v,u);
        }
        for(LL i=0;i<n;i++) scanf("%I64d",&a[i]);
        printf("Case #%I64d:\n",kcase++);
        init(n);
        while(m--)
        {
            LL op;
            scanf("%I64d",&op);
            if(op==1)
            {
                LL pos;
                scanf("%I64d",&pos);
                printf("%I64d\n",query(1,1,n,c[pos].l,c[pos].r));
            }
            else
            {
                LL pos,value;
                scanf("%I64d%I64d",&pos,&value);
                update(1,1,n,c[pos].l,c[pos].r,value-a[pos]);
                a[pos]=value;
            }
        }
    }
    return 0;
}


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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值