首页 > 其他 > 详细

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

时间:2020-02-02 12:30:05      阅读:243      评论:0      收藏:0      [点我收藏+]

[ZJOI2008]树的统计(luogu)

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 本身。

输入格式

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

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

接下来一行 n 个整数,第 i 个整数 w_i? 表示节点 i 的权值。接下来 1 行,为一个整数 q,表示操作的总数。

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

输出格式

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

Solution

模板题。。。

Code

 

#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <vector>
using namespace std;
const int N=3e4+10;
vector <int> link[N];
struct node
{
    int l,r,lc,rc,sum,ma;
}f[N*2];
int fa[N],top[N],son[N],dfn[N],size[N],n,q,a,b,cnt,tot,rt,d[N],deep[N];
char s[100];
void dfs1(int u,int fat)
{
    size[u]=1,fa[u]=fat,deep[u]=deep[fat]+1;
    int siz=link[u].size();
    for(int i=0;i<siz;i++)
    {
        int v=link[u][i];
        if(v==fa[u]) continue;
        dfs1(v,u),size[u]+=size[v];
        if(son[u]==0 || size[son[u]]<size[v]) son[u]=v;
    }
}
void dfs2(int u)
{
    dfn[u]=++cnt;
    if(son[u])
    {
        top[son[u]]=top[u],dfs2(son[u]);
        int siz=link[u].size();
        for(int i=0;i<siz;i++)
        {
            int v=link[u][i];
            if(v==fa[u] || v==son[u]) continue;
            top[v]=v,dfs2(v);
        }
    }
}
void push_up(int g)
{
    int lc=f[g].lc,rc=f[g].rc;
    if(lc==0) return ;
    f[g].ma=max(f[lc].ma,f[rc].ma);
    f[g].sum=f[lc].sum+f[rc].sum;
}
void build(int &g,int l,int r)
{
    g=++tot,f[g].l=l,f[g].r=r;
    if(l==r)
    {
        f[g].ma=f[g].sum=d[l];
        return ;
    }
    int mid=(l+r)>>1;
    build(f[g].lc,l,mid);
    build(f[g].rc,mid+1,r);
    push_up(g);
}
void change(int g,int x,int y)
{
    if(f[g].l==f[g].r)
        f[g].ma=f[g].sum=y;
    else
    {
        int mid=(f[g].l+f[g].r)>>1;
        if(x<=mid) change(f[g].lc,x,y);
        else change(f[g].rc,x,y);
        push_up(g);
    }
}
int get_max(int g,int l,int r)
{
    if(f[g].l>=l && f[g].r<=r)
        return f[g].ma;
    else
    {
        int mid=(f[g].l+f[g].r)>>1;
        if(r<=mid) return get_max(f[g].lc,l,r);
        else if(l>mid) return get_max(f[g].rc,l,r);
        else return max(get_max(f[g].lc,l,mid),get_max(f[g].rc,mid+1,r));
    }
}
int get_sum(int g,int l,int r)
{
    if(f[g].l>=l && f[g].r<=r)
        return f[g].sum;
    else
    {
        int mid=(f[g].l+f[g].r)>>1;
        if(r<=mid) return get_sum(f[g].lc,l,r);
        else if(l>mid) return get_sum(f[g].rc,l,r);
        else return get_sum(f[g].lc,l,mid)+get_sum(f[g].rc,mid+1,r);
    }
}
int Get_sum(int x,int y)
{
    int ans=0;
    int px=top[x],py=top[y];
    while(px!=py)
        if(deep[px]>deep[py])
        {
            ans+=get_sum(rt,dfn[px],dfn[x]);
            x=fa[px],px=top[x];
        }
        else
        {
            ans+=get_sum(rt,dfn[py],dfn[y]);
            y=fa[py],py=top[y];
        }
    if(dfn[x]<dfn[y]) ans+=get_sum(rt,dfn[x],dfn[y]);
    else ans+=get_sum(rt,dfn[y],dfn[x]);
    return ans;
}
int Get_max(int x,int y)
{
    int ans=-1<<30;
    int px=top[x],py=top[y];
    while(px!=py)
        if(deep[px]>deep[py])
        {
            ans=max(ans,get_max(rt,dfn[px],dfn[x]));
            x=fa[px],px=top[x];
        }
        else
        {
            ans=max(ans,get_max(rt,dfn[py],dfn[y]));
            y=fa[py],py=top[y];
        }
    if(dfn[x]<dfn[y]) ans=max(ans,get_max(rt,dfn[x],dfn[y]));
    else ans=max(ans,get_max(rt,dfn[y],dfn[x]));
    return ans;
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<n;i++)
    {
        scanf("%d%d",&a,&b);
        link[a].push_back(b);
        link[b].push_back(a);
    }
    dfs1(1,0),top[1]=1,dfs2(1);
    for(int i=1;i<=n;i++)
        scanf("%d",&d[dfn[i]]);
    build(rt,1,cnt);
    scanf("%d",&q);
//CHANGE u t :把节点 u权值改为 t;
//QMAX u v :询问点 u到点 v路径上的节点的最大权值;
//QSUM u v :询问点 u到点 v路径上的节点的权值和。
    while(q--)
    {
        scanf("%s",s);
        scanf("%d%d",&a,&b);
        if(s[0]==C)
            change(rt,dfn[a],b);
        else if(s[1]==M)
            printf("%d\n",Get_max(a,b));
        else printf("%d\n",Get_sum(a,b));
    }
    return 0;
}

 

 

 

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

原文:https://www.cnblogs.com/hsez-cyx/p/12251060.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!