洛谷 P2590 [ZJOI2008]树的统计(树链剖分)

Posted Styx-ferryman

tags:

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

题目描述
一棵树上有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本身

输入输出格式
输入格式:
输入文件的第一行为一个整数n,表示节点的个数。

接下来n – 1行,每行2个整数a和b,表示节点a和节点b之间有一条边相连。

接下来一行n个整数,第i个整数wi表示节点i的权值。

接下来1行,为一个整数q,表示操作的总数。

接下来q行,每行一个操作,以“CHANGE u t”或者“QMAX u v”或者“QSUM u v”的形式给出。

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

输入输出样例
输入样例#1:
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
输出样例#1:
4
1
2
2
10
6
5
6
5
16
说明
对于100%的数据,保证1<=n<=30000,0<=q<=200000;中途操作中保证每个节点的权值w在-30000到30000之间。

题解:我懒得写一棵线段树两种操作了,所以索性写了两棵线段树,一棵 清蒸  求区间最大值,一棵红烧 求区间和

单点修改的时候,就同时修改两棵树。查询就是最经典的路径查询啦~

代码写了4k,还暗自窃喜自己终于写了一长度4k的代码,回去一看,什么鬼,我树剖模板题都写的比这个长?

也是醉了,代码如下:

#include<cstdio>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
#define lson root<<1
#define rson root<<1|1
using namespace std;

struct node
{
    int m,l,r;
} tr_sum[120120],tr_max[120120];
int size[30030],deep[30030],fa[30030],son[30030],id[30030],top[30030],w[30030],c[30030],cnt;
vector<int> g[30030];

void push_up_sum(int root)
{
    tr_sum[root].m=tr_sum[lson].m+tr_sum[rson].m;
}

void push_up_max(int root)
{
    tr_max[root].m=max(tr_max[lson].m,tr_max[rson].m);
}

void build_sum(int root,int l,int r)
{
    if(l==r)
    {
        tr_sum[root].l=l;
        tr_sum[root].r=r;
        tr_sum[root].m=w[l];
        return ;
    }
    tr_sum[root].l=l;
    tr_sum[root].r=r;
    int mid=(l+r)>>1;
    build_sum(lson,l,mid);
    build_sum(rson,mid+1,r);
    push_up_sum(root);
}

void build_max(int root,int l,int r)
{
    if(l==r)
    {
        tr_max[root].l=l;
        tr_max[root].r=r;
        tr_max[root].m=w[l];
        return ;
    }
    tr_max[root].l=l;
    tr_max[root].r=r;
    int mid=(l+r)>>1;
    build_max(lson,l,mid);
    build_max(rson,mid+1,r);
    push_up_max(root);
}

void update(int root,int x,int val)
{
    if(x==tr_sum[root].l&&x==tr_sum[root].r)
    {
        tr_sum[root].m=val;
        tr_max[root].m=val;
        return ;
    }
    int mid=(tr_sum[root].l+tr_sum[root].r)>>1;
    if(x>mid)
    {
        update(rson,x,val);
    }
    else
    {
        update(lson,x,val);
    }
    push_up_sum(root);
    push_up_max(root);
}

int query_sum(int root,int l,int r)
{
    if(l==tr_sum[root].l&&r==tr_sum[root].r)
    {
        return tr_sum[root].m;
    }
    int mid=(tr_sum[root].l+tr_sum[root].r)>>1;
    if(l>mid)
    {
        return query_sum(rson,l,r);
    }
    else
    {
        if(r<=mid)
        {
            return query_sum(lson,l,r);
        }
        else
        {
            return query_sum(lson,l,mid)+query_sum(rson,mid+1,r);
        }
    }
}

int query_max(int root,int l,int r)
{
    if(l==tr_max[root].l&&r==tr_max[root].r)
    {
        return tr_max[root].m;
    }
    int mid=(tr_max[root].l+tr_max[root].r)>>1;
    if(l>mid)
    {
        return query_max(rson,l,r);
    }
    else
    {
        if(r<=mid)
        {
            return query_max(lson,l,r);
        }
        else
        {
            return max(query_max(lson,l,mid),query_max(rson,mid+1,r));
        }
    }
}

void dfs1(int now,int f,int dep)
{
    fa[now]=f;
    deep[now]=dep;
    size[now]=1;
    int maxson=-1;
    for(int i=0; i<g[now].size(); i++)
    {
        if(g[now][i]==f)
        {
            continue;
        }
        dfs1(g[now][i],now,dep+1);
        size[now]+=size[g[now][i]];
        if(size[g[now][i]]>maxson)
        {
            son[now]=g[now][i];
            maxson=size[g[now][i]];
        }
    }
}

void dfs2(int now,int topf)
{
    id[now]=++cnt;
    w[cnt]=c[now];
    top[now]=topf;
    if(!son[now])
    {
        return ;
    }
    dfs2(son[now],topf);
    for(int i=0; i<g[now].size(); i++)
    {
        if(g[now][i]==fa[now]||g[now][i]==son[now])
        {
            continue;
        }
        dfs2(g[now][i],g[now][i]);
    }
}

int path_query_max(int x,int y)
{
    int ans=-100000;
    while(top[x]!=top[y])
    {
        if(deep[top[x]]<deep[top[y]])
        {
            swap(x,y);
        }
        ans=max(ans,query_max(1,id[top[x]],id[x]));
        x=fa[top[x]];
    }
    if(deep[x]>deep[y])
    {
        swap(x,y);
    }
    ans=max(ans,query_max(1,id[x],id[y]));
    return ans;
}

int path_query_sum(int x,int y)
{
    int ans=0;
    while(top[x]!=top[y])
    {
        if(deep[top[x]]<deep[top[y]])
        {
            swap(x,y);
        }
        ans+=query_sum(1,id[top[x]],id[x]);
        x=fa[top[x]];
    }
    if(deep[x]>deep[y])
    {
        swap(x,y);
    }
    ans+=query_sum(1,id[x],id[y]);
    return ans;
}

int main()
{
    int n,m;
    scanf("%d",&n);
    for(int i=1; i<=n-1; i++)
    {
        int from,to;
        scanf("%d%d",&from,&to);
        g[from].push_back(to);
        g[to].push_back(from);
    }
    for(int i=1; i<=n; i++)
    {
        scanf("%d",&c[i]);
    }
    dfs1(1,0,1);
    dfs2(1,1);
    build_sum(1,1,n);
    build_max(1,1,n);
    scanf("%d",&m);
    char s[10];
    int u,v;
    for(int i=1; i<=m; i++)
    {
        scanf("\n%s %d %d",s,&u,&v);
        if(s[0]==C)
        {
            update(1,id[u],v);
        }
        if(s[0]==Q)
        {
            if(s[1]==S)
            {
                printf("%d\n",path_query_sum(u,v));
            }
            if(s[1]==M)
            {
                printf("%d\n",path_query_max(u,v));
            }
        }
    }
}

 

以上是关于洛谷 P2590 [ZJOI2008]树的统计(树链剖分)的主要内容,如果未能解决你的问题,请参考以下文章

洛谷 P2590 [ZJOI2008]树的统计(树链剖分)

P2590 [ZJOI2008]树的统计(树链剖分)

P2590 [ZJOI2008]树的统计(LCT)

P2590 [ZJOI2008]树的统计

P2590 [ZJOI2008]树的统计

P2590 [ZJOI2008]树的统计