zoukankan      html  css  js  c++  java
  • 1036: [ZJOI2008]树的统计Count(树链剖分

    题目传送门:[ZJOI2008]树的统计Count

    题目大意:

    一棵树上有n个节点,每个节点都有一个权值w。进行以下的一些操作

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

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

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

    分析:

    树链剖分入门题,线段树维护点权最大值mmax和区间和ssum即可

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int MAX=30005;
    #define INF 1<<29
    #define ls l,m,rt<<1
    #define rs m+1,r,rt<<1|1
    int head[MAX],cnt;
    int fa[MAX];          //fa[x] x点的父节点 
    int deep[MAX];        //deep[x]  记录树中x点的深度 
    int size[MAX];        //size[x]  记录x节点的子树节点个数 
    int son[MAX];        //son[x]   记录x节点的重儿子 
    int top[MAX];        //top[x]   记录x所在重链的顶端节点 
    int id[MAX];        //id[x]    记录x节点在线段树中的位置 
    int rk[MAX],tot;    //rk[x]       记录在线段树x位置的节点是什么节点,与id[x]相反   
    int n,x,y,a[MAX],q,u,v;
    char op[10];
    struct Tree{
        int mmax,ssum;    //最大值和区间和 
    }tree[MAX*4];
    struct Edge{
        int next,to;
    }edge[MAX*2];
    inline void add(int u,int v)
    {
        edge[cnt].to=v;
        edge[cnt].next=head[u];
        head[u]=cnt++;
    }
    inline int max(int a,int b)
    {
        return a>b?a:b;
    }
    void dfs1(int u,int f,int d)    //dfs1求出deep,fa,size,son数组
    {
        deep[u]=d;
        fa[u]=f;
        size[u]=1;
        for(int i=head[u];i!=-1;i=edge[i].next)
        {
            int v=edge[i].to;
            if(v!=fa[u])
            {
                dfs1(v,u,d+1);
                size[u]+=size[v];
                if(son[u]==-1||size[v]>size[son[u]])
                    son[u]=v;
            }
        }
    }
    void dfstop(int u,int t)    //dfstop 划分重链 
    {
        top[u]=t;
        id[u]=tot++;
        rk[id[u]]=u;
        if(son[u]==-1)return;
        dfstop(son[u],t);
        for(int i=head[u];i!=-1;i=edge[i].next)
        {
            int v=edge[i].to;
            if(v!=son[u]&&v!=fa[u])
                dfstop(v,v);
        }
    }
    /*线段树部分*/
    void PushUp(int rt)
    {
        tree[rt].mmax=max(tree[rt<<1].mmax,tree[rt<<1|1].mmax);
        tree[rt].ssum=tree[rt<<1].ssum+tree[rt<<1|1].ssum;
    }
    void Build(int l,int r,int rt)
    {
        if(l==r)
        {
            tree[rt].ssum=a[rk[l]];
            tree[rt].mmax=a[rk[l]];
            return;
        }
        int m=l+r>>1;
        Build(ls),Build(rs);
        PushUp(rt);
    }
    void Update(int pos,int val,int l,int r,int rt)    //单点更新,将pos位置点值更新为val 
    {
        if(l==r)
        {
            tree[rt].mmax=val;
            tree[rt].ssum=val;
            return;
        }
        int m=l+r>>1;
        if(pos<=m)Update(pos,val,ls);
        else Update(pos,val,rs);
        PushUp(rt);
    }
    int QMAX(int L,int R,int l,int r,int rt)        //查询[l,r]区间最大值 
    {
        if(L<=l&&r<=R)
            return tree[rt].mmax;
        int m=l+r>>1;
        int ans=-INF;
        if(L<=m)ans=max(ans,QMAX(L,R,ls));
        if(R>m)ans=max(ans,QMAX(L,R,rs));
        return ans;
    }
    int QSUM(int L,int R,int l,int r,int rt)        //查询[l,r]区间和 
    {
        if(L<=l&&r<=R)
            return tree[rt].ssum;
        int m=l+r>>1;
        int ans=0;
        if(L<=m)ans+=QSUM(L,R,ls);
        if(R>m)ans+=QSUM(L,R,rs);
        return ans;
    }
    int solveMax(int x,int y)            //查询x->y路径节点最大值 
    {
        int res=-INF;
        while(top[x]!=top[y])
        {
            if(deep[top[x]]<deep[top[y]])
                swap(x,y);
            res=max(res,QMAX(id[top[x]],id[x],1,tot,1));
            x=fa[top[x]];
        }
        if(id[x]>id[y])swap(x,y);
        res=max(res,QMAX(id[x],id[y],1,tot,1));
        return res;
    }
    int solveSum(int x,int y)        //查询x->y路径节点的权值和 
    {
        int res=0;
        while(top[x]!=top[y])
        {
            if(deep[top[x]]<deep[top[y]])
                swap(x,y);
            res+=QSUM(id[top[x]],id[x],1,tot,1);
            x=fa[top[x]];
        }
        if(id[x]>id[y])swap(x,y);
        res+=QSUM(id[x],id[y],1,tot,1);
        return res;
    }
    void init()
    {
        memset(head,-1,sizeof(head));cnt=0;
        memset(son,-1,sizeof(son));tot=1;
        memset(a,0,sizeof(a));
        memset(tree,0,sizeof(tree));
    }
    int main()
    {
        init();
        scanf("%d",&n);
        for(int i=1;i<n;i++)
        {
            scanf("%d%d",&u,&v);
            add(u,v);add(v,u);
        }
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]);
            
        dfs1(1,-1,0);dfstop(1,1);    
        Build(1,tot,1);
        scanf("%d",&q);
        while(q--)
        {
            scanf("%s",op);
            scanf("%d%d",&x,&y);
            if(op[1]=='M')printf("%d
    ",solveMax(x,y));
            if(op[1]=='S')printf("%d
    ",solveSum(x,y));
            if(op[1]=='H')Update(id[x],y,1,tot,1);
        }
        return 0;
    }

    总结:很普通的树链剖分裸题,但是写的时候莫名其妙挂掉..一直无法通过,最后莫名其妙又过了,很奇怪QAQ

  • 相关阅读:
    SSH_框架整合2—查询显示
    SSH_框架整合1
    eclipse中tomcat发布失败(Could not delete May be locked by another process)原因及解决办法
    错误:javax.servlet.jsp.PageContext can not be to a type
    链表【6】
    欢迎使用CSDN-markdown编辑器
    剑指offer系列62---两个链表的公共结点
    剑指offer系列61---数组中的逆序对
    Git常用命令大全
    vue脚手架搭建的具体步骤
  • 原文地址:https://www.cnblogs.com/LjwCarrot/p/10810164.html
Copyright © 2011-2022 走看看