P2590 [ZJOI2008]树的统计

操作:

I. CHANGE u t : 把结点u的权值改为t

II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值

III. QSUM u v: 询问从点u到点v的路径上的节点的权值和

标签:树剖+线段树 模板题。

转化一下题意:

操作1:单点修改。

操作2:利用树剖求LCA的过程求经过的点的权值的最大值。

操作3:利用树剖求LCA的过程累加经过的点的权值之和。

Code:

#include<cstdio>
#include<iostream>
#include<string>
#define ri register int
using namespace std;

const int MAXN=60020;
int n,m,q,u[MAXN],v[MAXN],w[MAXN],fst[MAXN],nxt[MAXN],num,t;
int fa[MAXN],deep[MAXN],siz[MAXN],son[MAXN],cmax[MAXN],top[MAXN],dfn[MAXN],rk[MAXN],cur,a[MAXN];
int l[MAXN<<2],r[MAXN<<2],maxn[MAXN<<2],sum[MAXN<<2];
string ss;

void dfs1(int x,int father,int dep)
{
    fa[x]=father,deep[x]=dep,siz[x]=1;
    for(ri k=fst[x];k>0;k=nxt[k])
        if(v[k]!=father)
        {
            dfs1(v[k],x,dep+1);
            if(siz[v[k]]>cmax[x])	cmax[x]=siz[v[k]],son[x]=v[k];
            siz[x]+=siz[v[k]];
        }
}

void dfs2(int x,int anc)
{
    top[x]=anc,dfn[x]=++cur,rk[cur]=x,a[cur]=w[x];
    if(son[x]!=0)	dfs2(son[x],anc);
    for(ri k=fst[x];k>0;k=nxt[k])
        if(v[k]!=fa[x]&&v[k]!=son[x])	dfs2(v[k],v[k]);
}

void pushup(int p)
{
    sum[p]=sum[p <<1]+sum[p <<1|1];
    maxn[p]=max(maxn[p <<1],maxn[p <<1|1]);	
}

void build(int p,int lft,int rit)
{
    l[p]=lft,r[p]=rit;
    if(lft==rit)	{ sum[p]=a[lft]; maxn[p]=a[lft]; return; }
    int mid=(lft+rit)>>1;
    build(p <<1,lft,mid);
    build(p <<1|1,mid+1,rit);
    pushup(p);
}

void update(int p,int pla,int k)
{
    if(l[p]==pla&&r[p]==pla)
    {
        sum[p]=k,maxn[p]=k;
        return; 
    }
    if(pla<=r[p <<1])    update(p <<1,pla,k);
    if(l[p <<1|1]<=pla)    update(p <<1|1,pla,k);
    pushup(p);
}

int qmax(int p,int lft,int rit)
{
    if(lft<=l[p]&&r[p]<=rit)	return maxn[p];
    int ans=-1e9;
    if(lft<=r[p <<1])    ans=qmax(p <<1,lft,rit);
    if(l[p <<1|1]<=rit)	   ans=max(ans,qmax(p <<1|1,lft,rit));
    return ans;	
}

int LCAmax(int x,int y)
{
    int ans=-1e9;
    while(top[x]!=top[y])
    {
        if(deep[top[x]]<deep[top[y]])	swap(x,y);
        ans=max(ans,qmax(1,dfn[top[x]],dfn[x]));
        x=fa[top[x]];
    }
    if(deep[x]<deep[y])	swap(x,y);
    ans=max(ans,qmax(1,dfn[y],dfn[x]));
    return ans;	
}

int qsum(int p,int lft,int rit)
{
    if(lft<=l[p]&&r[p]<=rit)	return sum[p];
    int ans=0;
    if(lft<=r[p <<1])    ans=qsum(p <<1,lft,rit);
    if(l[p <<1|1]<=rit)	   ans+=qsum(p <<1|1,lft,rit);
    return ans;
}

int LCAsum(int x,int y)
{
    int ans=0;
    while(top[x]!=top[y])
    {
        if(deep[top[x]]<deep[top[y]])	swap(x,y);
        ans+=qsum(1,dfn[top[x]],dfn[x]);
        x=fa[top[x]];
    }
    if(deep[x]<deep[y])	swap(x,y);
    ans+=qsum(1,dfn[y],dfn[x]);
    return ans;
}

int main()
{
    scanf("%d",&n);
    m=(n-1)<<1;
    for(ri i=1;i<=m;i+=2)
    {
        scanf("%d%d",&u[i],&v[i]);
        nxt[i]=fst[u[i]],fst[u[i]]=i;
        u[i+1]=v[i],v[i+1]=u[i];
        nxt[i+1]=fst[u[i+1]],fst[u[i+1]]=i+1;
    }
    for(ri i=1;i<=n;i++)	scanf("%d",&w[i]);
    dfs1(1,1,0);
    dfs2(1,1);
    build(1,1,n);
    scanf("%d",&q);
    for(int i=1;i<=q;i++)
    {
        cin>>ss>>num>>t;
        if(ss=="CHANGE")    update(1,dfn[num],t);
        if(ss=="QMAX")    cout<<LCAmax(num,t)<<'\n';
        if(ss=="QSUM")    cout<<LCAsum(num,t)<<'\n';
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值