人生有信仰 数据有梯度 暴力不爆零


模板 -- 树链剖分

树链剖分

题目描述

一棵树有n个节点,每个节点有一个点权ai,共有m个操作:
操作编号
操作格式
说明
1.更新
UPDATE p x
把点p的权值修改为x
2.查询最大
MAX p q
查询pq路径中最大点权
3.查询和
SUM p q
查询pq路径中点权和

 

输入

       第一行两个整数nm
       接下来一行中n个整数表示初始点权;
       接下来行中每行两个整数pq,表示pq之间有一条边相连;
       接下来m行每行一个操作如上表所示。

输出

对于每一个查询操作,输出一行包含一个整数为对应的答案。

样例输入

4 3
3 6 8 5
1 2
1 3
2 4
MAX 1 4
UPDATE 1 5
SUM 1 3

样例输出

6
13

提示

 

#include<cstdio>
#include<iostream>
using namespace std;
#define N 100010
inline int max(int a,int b){return a>b?a:b;}
void swap(int &a,int &b){int c=a^b;b=b^c;a=a^c;}
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
struct qaz{int fro,to;}e[N<<1];
int tot[N],siz[N],top[N],son[N],dep[N],fa[N],tid[N],tim,rrank[N],lj[N],cnt;
void add(int a,int b){e[++cnt].fro=lj[a];e[cnt].to=b;lj[a]=cnt;}
void dfs1(int u,int father,int d)
{
    dep[u]=d;
    fa[u]=father;
    siz[u]=1;
    for(int i=lj[u];i;i=e[i].fro)
    {
        int v=e[i].to;
        if(v!=father)
        {
            dfs1(v,u,d+1);  siz[u]+=siz[v];
            if(son[u]==-1||siz[son[u]]<siz[v]) son[u]=v;
        }
    }
}
void dfs2(int u,int tp)
{
    top[u]=tp;
    tid[u]=++tim;
    rrank[tim]=u;
    if(son[u]==-1) return;
    dfs2(son[u],tp);
    for(int i=lj[u];i;i=e[i].fro)
    {
        int v=e[i].to;
        if(son[u]!=v&&v!=fa[u]) dfs2(v,v);
    }
}
int n,m,p,q,a[N];
char ss;
struct tree{int l,r,maxx,sum;}tr[N<<2];
void pu(int x)
{
    tr[x].maxx=max(tr[x<<1].maxx,tr[x<<1|1].maxx);
    tr[x].sum=tr[x<<1].sum+tr[x<<1|1].sum;
}
void build(int l,int r,int x)
{
    tr[x].l=l;tr[x].r=r;
    if(l==r)
    {
        tr[x].maxx=a[rrank[l]];
        tr[x].sum=a[rrank[l]];
        return;
    }
    int mid=(l+r)>>1;
    build(l,mid,x<<1);build(mid+1,r,x<<1|1);
    pu(x);
}
void xg(int c,int k,int x)
{
    if(tr[x].l==tr[x].r)
    {
        tr[x].sum=tr[x].maxx=k;
        return;
    }
    int mid=(tr[x].l+tr[x].r)>>1;
    if(c<=mid) xg(c,k,x<<1);
    else xg(c,k,x<<1|1);
    pu(x);
}
inline int fdmax(int l,int r,int x)
{
    if(tr[x].l==l&&tr[x].r==r) return tr[x].maxx;
    int mid=(tr[x].l+tr[x].r)>>1;
    if(r<=mid) return fdmax(l,r,x<<1);
    else if(l>mid) return fdmax(l,r,x<<1|1);
    else return max(fdmax(l,mid,x<<1),fdmax(mid+1,r,x<<1|1));
}
inline int fdsum(int l,int r,int x)
{
    if(tr[x].l==l&&tr[x].r==r) return tr[x].sum;
    int mid=(tr[x].l+tr[x].r)>>1;
    if(r<=mid) return fdsum(l,r,x<<1);
    else if(l>mid) return fdsum(l,r,x<<1|1);
    else return fdsum(l,mid,x<<1)+fdsum(mid+1,r,x<<1|1);
}

int main()
{
    n=read();m=read();
    for(int i=1;i<=n;i++) a[i]=read();
    for(int i=1;i<n;i++)
    {
        p=read();q=read();
        add(p,q);add(q,p);
    }
    for(int i=0;i<=n;i++) son[i]=-1;
    dfs1(1,0,0);
    dfs2(1,1);
    build(1,n,1);
    for(int i=0;i<m;i++)
    {
        ss=' ';
        while(ss<'A'||ss>'Z') ss=getchar();
        p=read();q=read();
        int tmp=0;
        if(ss=='U') xg(tid[p],q,1);
        else if(ss=='M')
        {
            while(top[p]!=top[q])
            {
                if(dep[top[p]]<dep[top[q]]) swap(p,q);
                tmp=max(tmp,fdmax(tid[top[p]],tid[p],1));
                p=fa[top[p]];
            }
            if(dep[p]>dep[q]) swap(p,q);
            tmp=max(tmp,fdmax(tid[p],tid[q],1));
        }
        else if(ss=='S')
        {
            while(top[p]!=top[q])
            {
                if(dep[top[p]]<dep[top[q]]) swap(p,q);
                tmp+=fdsum(tid[top[p]],tid[p],1);
                p=fa[top[p]];
            }
            if(dep[p]>dep[q]) swap(p,q);
            tmp+=fdsum(tid[p],tid[q],1);
        }
        if(ss!='U')printf("%d\n",tmp);
    }
    return 0;
}

 

 

posted @ 2017-02-24 16:02  lkhll  阅读(218)  评论(0编辑  收藏  举报