zoukankan      html  css  js  c++  java
  • [ZJOI2008]树的统计

    题目描述

    一棵树上有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个整数wi表示节点i的权值。

    接下来1行,为一个整数q,表示操作的总数。

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

    输出格式:

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

    输入输出样例

    输入样例#1: 复制
    4
    1 2
    2 3
    4 1
    4 2 1 3
    12
    QMAX 3 4
    QMAX 3 3
    QMAX 3 2
    QMAX 2 3
    QSUM 3 4
    QSUM 2 1
    CHANGE 1 5
    QMAX 3 4
    CHANGE 3 6
    QMAX 3 4
    QMAX 2 4
    QSUM 3 4
    
    输出样例#1: 复制
    4
    1
    2
    2
    10
    6
    5
    6
    5
    16
    

    说明

    对于100%的数据,保证1<=n<=30000,0<=q<=200000;中途操作中保证每个节点的权值w在-30000到30000之间。


    题解

        考线段树的好吧

        树剖预处理一下再加线段树的最大值查询加路径和查询就没了


    #include<cstdio>
    #include<cmath>
    #include<cstring>
    #include<algorithm>
    #include<iostream>
    using namespace std;
    const int N=2000001;
    struct node{ 
        int to,next;
    }e[N] ;
    int head[N],num,ch[N],n,m;
    int lazy[N],sum[N],maxn[N];
    int size[N],dep[N],son[N],fa[N],tot,l[N],a[N],top[N];
    char ss[11];
    void add(int from,int to)
    {     num++;
        e[num].to=to;
        e[num].next=head[from];
        head[from]=num;
    }
    void build(int root,int l,int r)
    {
        if(l==r)
        {
            //cout<<a[l]<<endl;
            maxn[root]=a[l];
            sum[root]=a[l];
            return ;
        }
        int mid=(l+r)>>1;
        build(root<<1,l,mid);
        build(root<<1|1,mid+1,r);
        sum[root]=sum[root<<1]+sum[root<<1|1];
        maxn[root]=max(maxn[root<<1],maxn[root<<1|1]);
        return ;
    }
    
    
    void update(int root,int left,int right,int l,int r,int k)
    {
        if(l>right||r<left)return ;
        if(l<=left&&right<=r)
        {
            sum[root]=k;
            //lazy[root]=k;
            maxn[root]=k;
            return ;
        }
        int mid=(left+right)>>1;
        //if(lazy[root])push(root,left,right);
        if(mid>=l) update(root<<1,left,mid,l,r,k);
        if(mid<r)  update(root<<1|1,mid+1,right,l,r,k);
        sum[root]=sum[root<<1]+sum[root<<1|1];
        maxn[root]=max(maxn[root<<1],maxn[root<<1|1]);
        return ;
    }
    
    int query1(int root,int left,int right,int l,int r)
    {
        if(l>right||r<left)return 0;
        if(l<=left&&r>=right)return sum[root];
        int mid=(left+right)>>1;
        int a=0,b=0;
        if(mid>=l) a=query1(root<<1,left,mid,l,r);
        if(mid<r)  b=query1(root<<1|1,mid+1,right,l,r);
        return a+b;
    }
    
    int query2(int root,int left,int right,int l,int r)
    {
        int ans=-1e8;
        if(l>right||r<left)return -1e8;
        if(l<=left&&r>=right)return maxn[root];
        int mid=(left+right)>>1;
        int a=-1e8,b=-1e8;
        if(mid>=l) a=query2(root<<1,left,mid,l,r);
        if(mid<r)  b=query2(root<<1|1,mid+1,right,l,r);
        return ans=max(ans,max(a,b));
    }
    void dfs1(int x)
    {
        size[x]=1;
        for(int i=head[x];i;i=e[i].next)
        {
            int v=e[i].to;
            if(!dep[v])
            {
                dep[v]=dep[x]+1;
                fa[v]=x;
                dfs1(v);
                size[x]+=size[v];
                if(size[v]>size[son[x]])son[x]=v;
            }
        }
        return ;
    }
    
    void dfs2(int x,int t)
    {
    
        l[x]=++tot;a[tot]=ch[x];top[x]=t;
        if(son[x])dfs2(son[x],t);
        for(int i=head[x];i;i=e[i].next)
        {
            int v=e[i].to;
            if(v!=fa[x]&&v!=son[x])
            dfs2(v,v);
        }
        return ;
    }
    
    int cap(int x,int y,int f)
    {
        int maxx=0,fx=top[x],fy=top[y];
        if(f==2)maxx=-1e8-9;
        while(fx!=fy)
        {
            if(dep[fx]<dep[fy])
            {
                swap(x,y);swap(fx,fy);
            }
            if(f==1)maxx+=query1(1,1,n,l[fx],l[x]);
            else maxx=max(maxx,query2(1,1,n,l[fx],l[x]));
            x=fa[fx];fx=top[x];
           
        }
        if(dep[x]>dep[y])swap(x,y);
        if(f==1)maxx+=query1(1,1,n,l[x],l[y]);
        else maxx=max(query2(1,1,n,l[x],l[y]),maxx);
    
        return maxx;
    }
    
    int read()
    {
        int x=0,w=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
        while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
        return x*w;
    }
    
    int main()
    {
        memset(maxn,-127,sizeof(maxn));
        n=read();
        for(int i=1;i<n;i++)
        {
            int x,y;x=read();y=read();
            add(x,y);add(y,x);
        }
        for(int i=1;i<=n;i++)
        {
            ch[i]=read();
        }
    
        fa[1]=1;
        dep[1]=1;
        dfs1(1);
        dfs2(1,1);
    
        build(1,1,n);
        m=read();int x,y;
        for(int i=1;i<=m;i++)
        {
            scanf("%s",ss);
            if(ss[0]=='C')
            {
                x=read();y=read();
                update(1,1,n,l[x],l[x],y);
            }
            else if(ss[1]=='M')
            {
                x=read();y=read();
                printf("%d
    ",cap(x,y,2));
            }
            else 
            {
                x=read();y=read();
                printf("%d
    ",cap(x,y,1));
            }
        }
        return 0;
    }
  • 相关阅读:
    kb,mb
    搜狗浏览器“Alt+Z”(重新打开刚关闭的页面)失效的解决方案——使用“hkexplr”查看占用的快捷键
    在 Windows server 中备份数据、分区、磁盘,以及硬盘对拷——傲梅轻松备份2.1.0汉化破解技术员版
    使用了阵列卡的服务器,在Windows系统内看到硬盘的品牌、型号信息——aida64
    利用“VeraCrypt”创建加密卷(文件夹加密,较高强度)
    Windows下多个硬盘显示为一个分区的方案
    win10企业版400年密钥
    Easy2Boot——可制作多包含多个原版系统(.iso)的工具
    第三方资源管理器——XYplorer(可自定义文件夹颜色)
    Windows10专业版(版本号:21H1)安装后的设置
  • 原文地址:https://www.cnblogs.com/hhh1109/p/8780650.html
Copyright © 2011-2022 走看看