【bzoj 1036】 [ZJOI2008]树的统计Count

本文介绍了一种针对树形结构数据进行高效查询和更新的算法实现。通过离线处理和区间查询的方式,解决了树上两点间节点权值的最大值及总和问题,并支持节点权值的动态更改。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

[ZJOI2008]树的统计Count

Time Limit: 10 Sec Memory Limit: 162 MB
Submit: 15802 Solved: 6447
[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
手速题,我一个老年选手就调了30min……

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 30005;
int rk[MAXN],loc[MAXN],cnt;
int sum[MAXN<<2],big[MAXN<<2];
int data[MAXN];
int h[MAXN],to[MAXN<<1],nx[MAXN<<1],len;
int dep[MAXN],ch[MAXN],top[MAXN],sz[MAXN],fa[MAXN];
int n,m;
char in[80];
const char sa[]={"QSUM"},sb[]={"QMAX"},sc[]={"CHANGE"};
struct ans{
    int summ,bigm;
};
void ins(int u,int v){
    len++;to[len]=v;nx[len]=h[u];h[u]=len;
    len++;to[len]=u;nx[len]=h[v];h[v]=len;
}
void pushup(int nd){
    sum[nd]=sum[nd<<1]+sum[nd<<1|1];
    big[nd]=max(big[nd<<1],big[nd<<1|1]);
}
void build(int rt,int l,int r){
    if(l==r){
        sum[rt]=big[rt]=data[loc[l]];
        return;
    }
    int mid=(l+r)>>1;
    build(rt<<1,l,mid);
    build(rt<<1|1,mid+1,r);
    pushup(rt);
}
int lca(int a,int b){
    while(top[a]!=top[b]){
        dep[top[a]] > dep[top[b]] ? a=fa[top[a]] : b=fa[top[b]]; 
    }
    return dep[a]<dep[b]?a:b;
}
ans query(int rt,int L,int R,int l,int r){
    //if(l>r)swap(l,r);
//  cout<<rt<<" "<<L<<" "<<R<<" "<<l<<" "<<r<<endl;
    ans ret=(ans){0,-0x7ffffff};
    if(l<=L && r>=R)
    {
        ret=(ans){sum[rt],big[rt]};
        return ret;
    }
    int mid=(L+R)>>1;
    if(l>mid)
    {
        return query(rt<<1|1,mid+1,R,l,r);
    }
    else if(r<=mid)
    {
        return query(rt<<1,L,mid,l,r);
    }
    else
    {
        ans _a,_b;
        _a=query(rt<<1,L,mid,l,mid);
        _b=query(rt<<1|1,mid+1,R,mid+1,r);
//      cout<<_a.summ<<" "<<_b.summ<<endl; 
        ret=(ans){_a.summ+_b.summ,max(_a.bigm,_b.bigm)};
    }
    return ret;
}
void modify(int rt,int l,int r,int loc,int d)
{
    if(l>r)swap(l,r);
    if(l==r)
    {
        sum[rt]=big[rt]=d;return;
    }
    int mid=(l+r)>>1;
    if(loc>mid)
    {
        modify(rt<<1|1,mid+1,r,loc,d);
    }
    else
    {
        modify(rt<<1,l,mid,loc,d);
    }
    pushup(rt);
}
void change(int loc,int t)
{
    modify(1,1,cnt,rk[loc],t);
}
/*
ans getans(int u,int v)
{
    int l=lca(u,v);
    ans ret=(ans){0,0},buf;
    while(top[u]!=top[l])
    {
        buf=query(1,1,cnt,rk[u],top[u]);
        u=fa[top[u]];
        ret.summ+=buf.summ;
        ret.bigm=max(ret.bigm,buf.bigm);
    }
    buf=query(1,1,cnt,rk[u],rk[l]);
    ret.summ+=buf.summ;
    ret.bigm=max(ret.bigm,buf.bigm);

    while(top[v]!=top[l])
    {
        buf=query(1,1,cnt,rk[v],top[v]);
        v=fa[top[v]];
        ret.summ+=buf.summ;
        ret.bigm=max(ret.bigm,buf.bigm);        
    }
    buf=query(1,1,cnt,rk[v],rk[l]);
    ret.summ+=buf.summ;
    ret.bigm=max(ret.bigm,buf.bigm);
    return ret; 
}
*/
ans getans(int u,int v)
{
    ans ret=(ans){0,-0x7ffffff};
    while(top[u] != top[v])
    {
    //  cout<<u<<" "<<v<<" "<<dep[u]<<" "<<dep[v]<<" "<<rk[top[u]]<<" "<<rk[u]<<endl;
        if(dep[top[u]] > dep[top[v]])
        {

            ans _b=query(1,1,cnt,rk[top[u]],rk[u]);
            ret.summ+=_b.summ;
            ret.bigm=max(ret.bigm,_b.bigm);
            u=fa[top[u]];
        }
        else
        {
            ans _b=query(1,1,cnt,rk[top[v]],rk[v]);
            ret.summ+=_b.summ;
            ret.bigm=max(ret.bigm,_b.bigm);
            v=fa[top[v]];
        //  cout<<"finished\n";           
        }
    }   
    if(dep[u]>dep[v])
    {
        swap(u,v);
    }
    //cout<<rk[u]<<" "<<rk[v]<<endl;
    ans _b=query(1,1,cnt,rk[u],rk[v]);
    //cout<<query(1,1,cnt,rk[1],rk[3]).summ<<endl;
//  cout<<_b.summ<<endl;
    ret.summ+=_b.summ;
    ret.bigm=max(ret.bigm , _b.bigm);
//  cout<<ret.summ<<endl;
    return ret;
}

void dfs1(int nd,int pr){
    fa[nd]=pr;
    dep[nd]=dep[pr]+1;
    sz[nd]=1;
    for(int i=h[nd];i;i=nx[i]){
        if(to[i] != fa[nd]){
            dfs1(to[i],nd);
            sz[nd]+=sz[to[i]];
            if(sz[to[i]] > sz[ch[nd]])
                ch[nd]=to[i];
        }
    }   
}
void dfs2(int nd,int tp){
    top[nd]=tp;
    rk[nd]=++cnt;
    loc[cnt]=nd;
    if(ch[nd]!=0)dfs2(ch[nd],tp);
    for(int i=h[nd];i;i=nx[i]){
        if(to[i]!=fa[nd] && to[i]!=ch[nd]){
            dfs2(to[i],to[i]);
        }
    }
}
int check()
{
    if(!strcmp(in,sa))return 1;
    if(!strcmp(in,sb))return 2;
    if(!strcmp(in,sc))return 3;
    return 233;
}
int main(){
//  freopen("bzoj_1036.in","r",stdin);
//  freopen("bzoj_1036.out","w",stdout);
    scanf("%d",&n);
    for(int i=1;i<=n-1;i++){
        int a,b;
        scanf("%d%d",&a,&b);
        ins(a,b);
    }
    for(int i=1;i<=n;i++)
        scanf("%d",&data[i]);
    dfs1(1,0);
    dfs2(1,1);
    //cout<<lca(4,3)<<endl;
    build(1,1,cnt);



//  cout<<query(1,1,n,rk[1],rk[top[1]]).bigm<<endl;




    scanf("%d",&m);






    /*
    for(int i=1;i<=n;i++)
        cout<<rk[i]<<" "; 
    */






    for(int i=1;i<=m;i++)
    {
        int a,b;
        scanf("%s %d %d",in,&a,&b);
        int f=check();
        ans rt;
        switch(f)
        {
            case 1:
                rt=getans(a,b);
                printf("%d\n",rt.summ); 
                break;
            case 2:
                rt=getans(a,b);
                printf("%d\n",rt.bigm);                 
                break;
            case 3:
                change(a,b);
                break;
            default:
                puts("233");
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值