zoukankan      html  css  js  c++  java
  • 模板 -- 树链剖分

    树链剖分

    题目描述

    一棵树有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
    ",tmp);
        }
        return 0;
    }

    版权声明:本文为博主原创文章,未经博主允许不得转载。

  • 相关阅读:
    jquery之empty()与remove()区别
    (四)快速排序
    (三)归并排序
    (二)希尔排序
    (一)冒泡排序、插入排序、选择排序
    四,JVM 自带工具之jvisualvm
    JAVA多线程之Volatiles
    JAVA多线程之线程池的使用
    CountDownLatch与CyclicBarrier的使用与区别
    乐观锁与悲观锁及其实现
  • 原文地址:https://www.cnblogs.com/lkhll/p/6438940.html
Copyright © 2011-2022 走看看