当前位置: 首页 > news >正文

[树链剖分]luogu P2590 ZJOI 树的统计

 

 

题目描述

一棵树上有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”的操作,每行输出一个整数表示要求输出的结果。

 

输入输出样例

输入样例
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
输出样例
4
1
2
2
10
6
5
6
5
16

说明

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

 

分析

由于单点修改,查询树上简单路径值,容易想到树链剖分。

 

#include <iostream>
#include <cstdio>
#include <cstring>
#define rep(i,a,b) for (i=a;i<=b;i++)
using namespace std;
struct Node {
    int val,sz,f,s,seg,top,dep;
}a[30001];
int scnt,rev[30001];
struct Edge {
    int u,v,nx;
}g[60001];
int cnt,list[30001];
struct Sect {
    int sum,max;
}t[120001];
int sm,mx;
int n,m;

void Add(int u,int v) {g[++cnt].u=u;g[cnt].v=v;g[cnt].nx=list[u];list[u]=cnt;}

void Dfs1(int x,int f) {
    a[x].f=f;a[x].dep=a[f].dep+1;a[x].sz=1;
    for (int i=list[x];i;i=g[i].nx)
    if (g[i].v!=f) {
        Dfs1(g[i].v,x);
        a[x].sz+=a[g[i].v].sz;
        if (a[g[i].v].sz>a[a[x].s].sz) a[x].s=g[i].v;
    }
}

void Dfs2(int x,int f) {
    int son=a[x].s;
    if (son) {
        a[son].seg=++scnt;
        rev[scnt]=son;
        a[son].top=a[x].top;
        Dfs2(son,x);
    }
    for (int i=list[x];i;i=g[i].nx)
    if (!a[g[i].v].top) {
        a[g[i].v].seg=++scnt;
        rev[scnt]=g[i].v;
        a[g[i].v].top=g[i].v;
        Dfs2(g[i].v,x);
    }
}

void Build(int x,int l,int r) {
    if (l==r) {
        t[x].max=t[x].sum=a[rev[l]].val;
        return;
    }
    int mid=l+r>>1;
    Build(x<<1,l,mid);Build((x<<1)+1,mid+1,r);
    t[x].max=max(t[x<<1].max,t[(x<<1)+1].max);
    t[x].sum=t[x<<1].sum+t[(x<<1)+1].sum;
}

void Change(int x,int l,int r,int val,int seg) {
    if (l>seg||seg>r) return;
    if (l==r&&l==seg) {
        t[x].max=t[x].sum=val;
        return;
    }
    int mid=l+r>>1;
    if (mid>=seg) Change(x<<1,l,mid,val,seg);
    if (mid+1<=seg) Change((x<<1)+1,mid+1,r,val,seg);
    t[x].sum=t[x<<1].sum+t[(x<<1)+1].sum;
    t[x].max=max(t[x<<1].max,t[(x<<1)+1].max);
}

void Query_In_Segment(int x,int l,int r,int ll,int rr) {
    if (r<ll||l>rr) return;
    if (ll<=l&&r<=rr) {
        sm+=t[x].sum;
        mx=max(mx,t[x].max);
        return;
    }
    int mid=l+r>>1;
    if (ll<=mid) Query_In_Segment(x<<1,l,mid,ll,rr);
    if (mid+1<=rr) Query_In_Segment((x<<1)+1,mid+1,r,ll,rr);
}

void Query_In_Tree(int x,int y) {
    int fx=a[x].top,fy=a[y].top;
    while (fx!=fy) {
        if (a[fx].dep<a[fy].dep) swap(x,y),swap(fx,fy);
        Query_In_Segment(1,1,scnt,a[fx].seg,a[x].seg);
        x=a[fx].f;fx=a[x].top;
    }
    if (a[x].dep>a[y].dep) swap(x,y);
    Query_In_Segment(1,1,scnt,a[x].seg,a[y].seg);
}

int main() {
    int i;
    char s[20];
    scanf("%d",&n);
    rep(i,1,n-1) {
        int u,v;
        scanf("%d%d",&u,&v);
        Add(u,v);Add(v,u);
    }
    rep(i,1,n) scanf("%d",&a[i].val);
    Dfs1(1,0);
    scnt=1;
    a[1].seg=a[1].top=rev[1]=1;
    Dfs2(1,0);
    Build(1,1,scnt);
    scanf("%d",&m);
    rep(i,1,m) {
        int u,v;
        scanf("%s",&s);
        scanf("%d%d",&u,&v);
        if (s[0]=='C') Change(1,1,scnt,v,a[u].seg); 
        if (s[0]=='Q') {
            sm=0;mx=-2147483647;
            Query_In_Tree(u,v);
            if (s[1]=='M') printf("%d\n",mx);
            else printf("%d\n",sm);
        }
    }
}
View Code

 

转载于:https://www.cnblogs.com/mastervan/p/9362632.html

相关文章:

  • linux中断线程化分析【转】
  • php linux 脚本语法解释
  • python之udp协议的套接字
  • PHP变量
  • AdTime:多屏互动 进化中的大数据营销
  • Unity2018新功能抢鲜 | Package Manager
  • 快递业频爆黑料,不如让机器人送货吧!
  • Java 基础 之 for 循环
  • BIND9 DoS漏洞CVE-2016-8864 绿盟科技发布技术分析与防护方案 北京有1435台设备受影响...
  • yum更新出错-解决
  • linux使用wget下载jdk并配置
  • 虚假信息成物联网“毒瘤”
  • 今天的考核题目: 你知道React和Vue的区别吗? skr,skr
  • 网易研究院汪源:MySQL或成为最大黑马
  • mysql_config_editor
  • [js高手之路]搞清楚面向对象,必须要理解对象在创建过程中的内存表示
  • [译]如何构建服务器端web组件,为何要构建?
  • CSS居中完全指南——构建CSS居中决策树
  • Druid 在有赞的实践
  • Java教程_软件开发基础
  • laravel with 查询列表限制条数
  • Map集合、散列表、红黑树介绍
  • vue2.0开发聊天程序(四) 完整体验一次Vue开发(下)
  • Webpack入门之遇到的那些坑,系列示例Demo
  • 第三十一到第三十三天:我是精明的小卖家(一)
  • 翻译--Thinking in React
  • 聚簇索引和非聚簇索引
  • 七牛云假注销小指南
  • 三分钟教你同步 Visual Studio Code 设置
  • 深入浏览器事件循环的本质
  • 算法-图和图算法
  • 通信类
  • hi-nginx-1.3.4编译安装
  • MPAndroidChart 教程:Y轴 YAxis
  • shell使用lftp连接ftp和sftp,并可以指定私钥
  • 直播平台建设千万不要忘记流媒体服务器的存在 ...
  • ( )的作用是将计算机中的信息传送给用户,计算机应用基础 吉大15春学期《计算机应用基础》在线作业二及答案...
  • (安卓)跳转应用市场APP详情页的方式
  • (二)基于wpr_simulation 的Ros机器人运动控制,gazebo仿真
  • (附源码)springboot课程在线考试系统 毕业设计 655127
  • (剑指Offer)面试题41:和为s的连续正数序列
  • (四)Linux Shell编程——输入输出重定向
  • (万字长文)Spring的核心知识尽揽其中
  • (一)Neo4j下载安装以及初次使用
  • (已解决)vue+element-ui实现个人中心,仿照原神
  • (自适应手机端)响应式新闻博客知识类pbootcms网站模板 自媒体运营博客网站源码下载
  • .gitignore文件设置了忽略但不生效
  • .NET Framework杂记
  • .net 设置默认首页
  • .net6Api后台+uniapp导出Excel
  • .NET分布式缓存Memcached从入门到实战
  • .NET设计模式(11):组合模式(Composite Pattern)
  • [ Linux 长征路第五篇 ] make/Makefile Linux项目自动化创建工具
  • [2013AAA]On a fractional nonlinear hyperbolic equation arising from relative theory
  • [C++]C++入门--引用