洛谷 P2590 [ZJOI2008]树的统计

Posted

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之间。

 

模版树剖 

屠龙宝刀点击就送

#include <ctype.h>
#include <cstdio>
#define N 50000

void read(int &x)
{
    x=0;
    bool f=0;
    char ch=getchar();
    while(!isdigit(ch)) {if(ch==-) f=1;ch=getchar();}
    while(isdigit(ch)) {x=x*10+ch-0;ch=getchar();}
    x=f?(~x)+1:x;
}
struct Edge
{
    int next,to;
}edge[N<<1];

struct Tree
{
    int l,r,dis,Max;
    Tree *left,*right;
    Tree()
    {
        left=right=NULL;
        dis=Max=0;
    }
}*root;
int dfn[N],Q,dis[N],head[N],cnt,n,top[N],fa[N],dep[N],tim,size[N],belong[N];
int max(int a,int b) {return a>b?a:b;} 
void add(int u,int v)
{
    ++cnt;
    edge[cnt].next=head[u];
    edge[cnt].to=v;
    head[u]=cnt;
}
void dfs1(int x)
{
    size[x]=1;
    dep[x]=dep[fa[x]]+1;
    for(int i=head[x];i;i=edge[i].next)
    {
        int v=edge[i].to;
        if(fa[x]!=v)
        {
            fa[v]=x;
            dfs1(v);
            size[x]+=size[v];
        }
    }
}
void dfs2(int x)
{
    belong[x]=++tim;
    dfn[tim]=x;
    int t=0;
    if(!top[x]) top[x]=x;
    for(int i=head[x];i;i=edge[i].next)
    {
        int v=edge[i].to;
        if(fa[x]!=v&&size[t]<size[v]) t=v;
    }
    if(t) top[t]=top[x],dfs2(t);
    for(int i=head[x];i;i=edge[i].next)
    {
        int v=edge[i].to;
        if(fa[x]!=v&&v!=t) dfs2(v);
    }
}
void build(Tree *&k,int l,int r)
{
    k=new Tree;
    k->l=l;k->r=r;
    if(l==r)
    {
        k->dis=k->Max=dis[dfn[l]];
        return;
    }
    int mid=(l+r)>>1;
    build(k->left,l,mid);
    build(k->right,mid+1,r);
    k->dis=k->left->dis+k->right->dis;
    k->Max=max(k->left->Max,k->right->Max);
}
void Tree_change(Tree *&k,int t,int z)
{
    if(k->l==k->r)
    {
        k->dis=k->Max=z;
        return;
    }
    int mid=(k->l+k->r)>>1;
    if(mid>=t) Tree_change(k->left,t,z);
    else Tree_change(k->right,t,z);
    k->dis=k->left->dis+k->right->dis;
    k->Max=max(k->left->Max,k->right->Max);
}
void swap(int &x,int &y)
{
    int tmp=y;
    y=x;
    x=tmp;
}
int Tree_Query_Max(Tree *&k,int l,int r)
{
    if(k->l==l&&k->r==r) return k->Max;
    int mid=(k->l+k->r)>>1;
    if(l>mid) return Tree_Query_Max(k->right,l,r);
    else if(r<=mid) return Tree_Query_Max(k->left,l,r);
    else return max(Tree_Query_Max(k->left,l,mid),Tree_Query_Max(k->right,mid+1,r));
}
int Chain_Query_Max(int x,int y)
{
    int ans=-0x7fffffff;
    for(;top[x]!=top[y];x=fa[top[x]])
    {
        if(dep[top[x]]<dep[top[y]]) swap(x,y);
        ans=max(ans,Tree_Query_Max(root,belong[top[x]],belong[x]));
    }
    if(belong[x]>belong[y]) swap(x,y);
    ans=max(ans,Tree_Query_Max(root,belong[x],belong[y]));
    return ans;
}
int Tree_Query_Sum(Tree *&k,int l,int r)
{
    if(k->l==l&&k->r==r) return k->dis;
    int mid=(k->l+k->r)>>1;
    if(l>mid) return Tree_Query_Sum(k->right,l,r);
    else if(r<=mid) return Tree_Query_Sum(k->left,l,r);
    else return Tree_Query_Sum(k->left,l,mid)+Tree_Query_Sum(k->right,mid+1,r);
}
int Chain_Query_Sum(int x,int y)
{
    int ans=0;
    for(;top[x]!=top[y];x=fa[top[x]])
    {
        if(dep[top[x]]<dep[top[y]]) swap(x,y);
        ans+=Tree_Query_Sum(root,belong[top[x]],belong[x]);
    }
    if(belong[x]>belong[y]) swap(x,y);
    ans+=Tree_Query_Sum(root,belong[x],belong[y]);
    return ans;
}
int main()
{
    read(n);
    for(int a,b,i=1;i<n;i++)
    {
        read(a);
        read(b);
        add(a,b);
        add(b,a);
    }
    for(int i=1;i<=n;i++) read(dis[i]);
    dfs1(1);
    dfs2(1);
    read(Q);
    root=new Tree;
    build(root,1,n);
    char str[11];
    for(int x,y;Q--;)
    {
        scanf("%s",str+1);
        if(str[1]==C)
        {
            read(x);
            read(y);
            Tree_change(root,belong[x],y);
        }
        else if(str[2]==M)
        {
            read(x);
            read(y);
            printf("%d\n",Chain_Query_Max(x,y));
        }
        else
        {
            read(x);
            read(y);
            printf("%d\n",Chain_Query_Sum(x,y));
        }
    }
    return 0;
}

 

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

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

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

P2590 [ZJOI2008]树的统计

P2590 [ZJOI2008]树的统计

P2590 [ZJOI2008]树的统计

P2590 [ZJOI2008]树的统计(LCT)