题目链接:https://loj.ac/problem/2195
解题思路
树链剖分+动态开点线段树。可以通过树链剖分将问题转化成询问序列上与起点相同宗教的权值总和及最大值,并且支持单点更新。这个问题可以用线段树解决,但一般线段树要开四倍空间,而且要维护不同宗教,所以空间肯定不够。但是我们可以动态开点,树上每个点最多对应logn个点,所以动态开点最多也就nlogn个点,空间就够了,就是牺牲了常数的时间去开点,在这是可以接受的。
AC代码

#include <iostream>
#include <stdio.h>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=1e5+5;
const int maxm=2e7+5;
const int inf=0x3f3f3f3f;
struct node
{int to,next;
}edge[maxn<<1];//链式前向星
int head[maxn],num[maxn],root[maxn];
struct Node
{int l,r,Max,Sum;//l是左儿子编号,r是右儿子的编号
}tree[maxm];
int cnt,n,q,len;
int get()//快读
{char c;int sign=1;while((c=getchar())<'0'||c>'9')if(c=='-')sign=-1;int res=c-'0';while((c=getchar())>='0'&&c<='9')res=res*10+c-'0';return res*sign;
}
void add(int x,int y)
{edge[++cnt].to=y;edge[cnt].next=head[x];head[x]=cnt;
}
int fa[maxn];//x在树中的父亲
int dep[maxn];//x在树中的深度
int size[maxn];//x的子树结点数(子树大小)
int son[maxn];//x的重儿子,即u->son[u]是重边
int top[maxn];//x所在重路径的顶部顶点(深度最小)
int seg[maxn];//x在线段树中的位置(下标)
int rev[maxn];//线段树中第x位置对应的树中结点编号,rev[seg[x]]=x
int w[maxn];
int zj[maxn];
int Ssum,Mmax;
void update(int &rt,int L,int R,int val,int pos)//val是评级,os你要添加的点的fs序
{if(!rt)rt=++len;tree[rt].Max=max(tree[rt].Max,val);tree[rt].Sum+=val;if(L==R)return ;int mid=(L+R)>>1;if(mid>=pos)update(tree[rt].l,L,mid,val,pos);elseupdate(tree[rt].r,mid+1,R,val,pos);
}
void remove(int &rt,int L,int R,int pos)
{if(L==R){tree[rt].Sum=tree[rt].Max=0;return ;}int mid=(L+R)>>1;if(mid>=pos)remove(tree[rt].l,L,mid,pos);elseremove(tree[rt].r,mid+1,R,pos);tree[rt].Sum=tree[tree[rt].l].Sum+tree[tree[rt].r].Sum;tree[rt].Max=max(tree[tree[rt].l].Max,tree[tree[rt].r].Max);
}
int querySum(int rt,int lb,int rb,int L,int R)
{if(R<lb||L>rb)return 0;if(L<=lb&&R>=rb)return tree[rt].Sum;int mid=(lb+rb)>>1;return querySum(tree[rt].l,lb,mid,L,R)+querySum(tree[rt].r,mid+1,rb,L,R);
}
int queryMax(int rt,int lb,int rb,int L,int R)
{if(R<lb||L>rb)return 0;if(L<=lb&&R>=rb)return tree[rt].Max;int mid=(lb+rb)>>1;return max(queryMax(tree[rt].l,lb,mid,L,R),queryMax(tree[rt].r,mid+1,rb,L,R));
}
void dfs1(int u,int f)//第一遍dfs,算出fa[],dep[],size[],son[]
{size[u]=1;fa[u]=f;dep[u]=dep[f]+1;for(int i=head[u];i;i=edge[i].next){int v=edge[i].to;if(v==f)continue;dfs1(v,u);size[u]+=size[v];//计算sizeif(size[v]>size[son[u]])//求重儿子son[u]=v;}
}
void dfs2(int u,int f)//第二遍dfs,算出top[],seg[],rev[]
{if(son[u])//先走重儿子,使重路径在线段树中的位置连续{seg[son[u]]=++seg[0];//根无法在这里赋值,所以根要在主程序赋值top[son[u]]=top[u];//如果(u,v)为重边,那么u和v在同一条重路径上rev[seg[0]]=son[u];dfs2(son[u],u);}for(int i=head[u];i;i=edge[i].next){int v=edge[i].to;if(top[v])//top[v]有值即是被遍历过continue;seg[v]=++seg[0];rev[seg[0]]=v;top[v]=v;//如果(u,v)是轻边,则v就是其所在重路径的顶部结点dfs2(v,u);}
}
void askSum(int x,int y,int zj)//路径询问
{int fx=top[x],fy=top[y];while(fx!=fy){if(dep[fx]<dep[fy])//选择深度较大的往上跳{swap(x,y);swap(fx,fy);}Ssum+=querySum(root[zj],1,n,seg[fx],seg[x]);//重路径对应区间[seg[fx],seg[x]]x=fa[fx];fx=top[x];}if(dep[x]>dep[y])swap(x,y);Ssum+=querySum(root[zj],1,n,seg[x],seg[y]);
}
void askMax(int x,int y,int zj)
{int fx=top[x],fy=top[y];while(fx!=fy){if(dep[fx]<dep[fy])//选择深度较大的往上跳{swap(x,y);swap(fx,fy);}Mmax=max(Mmax,queryMax(root[zj],1,n,seg[fx],seg[x]));//重路径对应区间[seg[fx],seg[x]]x=fa[fx];fx=top[x];}if(dep[x]>dep[y])swap(x,y);Mmax=max(Mmax,queryMax(root[zj],1,n,seg[x],seg[y]));
}
int main()
{n=get();q=get();for(int i=1;i<=n;++i){w[i]=get();zj[i]=get();}for(int i=1;i<n;++i){int x,y;x=get();y=get();add(x,y);add(y,x);}dfs1(1,0);seg[0]=seg[1]=top[1]=rev[1]=1;//根结点所在重路径的顶部结点一定还是根结点dfs2(1,0);for(int i=1;i<=n;++i)update(root[zj[i]],1,n,w[i],seg[i]);char str[20];while(q--){int x,y;scanf("%s",str);x=get();y=get();if(str[0]=='C'){if(str[1]=='C'){remove(root[zj[x]],1,n,seg[x]);update(root[y],1,n,w[x],seg[x]);zj[x]=y;}else{remove(root[zj[x]],1,n,seg[x]);update(root[zj[x]],1,n,y,seg[x]);w[x]=y;}}else{if(str[1]=='S'){Ssum=0;askSum(x,y,zj[x]);printf("%d\n",Ssum);}else{Mmax=0;askMax(x,y,zj[x]);printf("%d\n",Mmax);}}}return 0;
}

树链剖分(四)——旅行相关推荐

  1. 【bzoj 3531】 [Sdoi2014]旅行(树链剖分+树套树)

    3531: [Sdoi2014]旅行 Time Limit: 20 Sec  Memory Limit: 512 MB Submit: 1197  Solved: 576 [Submit][Statu ...

  2. P3313-[SDOI2014]旅行【树链剖分,线段树】

    正题 题目链接:https://www.luogu.com.cn/problem/P3313 题目大意 nnn个点的一棵树,每个点有一个颜色和权值,有操作 修改一个点的权值 修改一个点的颜色 询问一条 ...

  3. 归纳(四):树链剖分

    剖分的意义 能用线段树搞想要的信息. (其实可以只用来求LCA) 需要的东西 七个数组,在两次dfs中处理出来. dfs1: dep[]:深度 fa[]:父亲 son[]:重儿子 siz[]:子树大小 ...

  4. 洛谷P4482 [BJWC2018]Border 的四种求法 字符串,SAM,线段树合并,线段树,树链剖分,DSU on Tree...

    原文链接https://www.cnblogs.com/zhouzhendong/p/LuoguP4482.html 题意 给定一个字符串 S,有 q 次询问,每次给定两个数 L,R ,求 S[L.. ...

  5. 模板 - 图论 - 树链剖分

    今天来啃一下这个树剖吧. 模板题是要求这四个问题: 将树从x到y结点最短路径上所有节点的值都加上z 求树从x到y结点最短路径上所有节点的值之和 将以x为根节点的子树内所有节点值都加上z 求以x为根节点 ...

  6. 软件包管理器(树链剖分)

    Linux用户和OSX用户一定对软件包管理器不会陌生.通过软件包管理器,你可以通过一行命令安装某一个软件包,然后软件包管理器会帮助你从软件源下载软件包,同时自动解决所有的依赖(即下载安装这个软件包的安 ...

  7. 简单dfs序 + 树链剖分

    树链剖分 DFS序 先来讲一讲DFS序是什么东西,直接上图,方便理解. 估计巨巨们应该知道了DFS序的两个重要的东西,in,outin,outin,out数组. ininin数组就是这个点进入DFS的 ...

  8. 树链剖分概念及模板 + 例题 [POJ3237 tree + 软件包管理器]

    文章目录 概念 模板 例题1:软件包管理器 题目 题解 代码实现 例题2:POJ3237 tree 题目 题解 代码实现 概念 树链剖分主要是用于解决以下这两个问题. 1.更改树上点x到点y的最短路径 ...

  9. bzoj 4196 树链剖分 模板

    [Noi2015]软件包管理器 Time Limit: 10 Sec  Memory Limit: 512 MB Submit: 2135  Solved: 1232 [Submit][Status] ...

最新文章

  1. Python-爬取音悦台MV列表以及反爬虫方法
  2. MybatisPlus实现条件查询
  3. windows下mysql中文乱码_windows下mysql中文乱码, 配置解决方法
  4. LeetCode篇:1(两数之和)
  5. 车辆动力性经济性 matlab计算
  6. android 跑分,2018年10月国内Android手机安兔兔跑分性能排行榜
  7. MySQL的两个存储引擎--MyISAM和InnoDB
  8. sql server 锁与事务拨云见日(下)
  9. python md5加密解密_Python使用MD5加密算法对字符串进行加密操作示例
  10. java 沙盒模拟支付_网站对接paypal支付接口记录
  11. meteor---在合并打包多个文件ZIP下载的功能
  12. c语言实验报告字符数组,C语言实验报告《数组》
  13. c语言绝对值函数作用,C语言实现abs和fabs绝对值
  14. STL(标准模板库)
  15. 抽象类(abstract)
  16. Bluetooth Battery Monitor(蓝牙电量监控软件)
  17. 前端 下载文件简易方法(兼容IE)
  18. [转载]Malcolm的新书:Outliers
  19. Netty的编解码器
  20. 假如生活欺骗了你 (普希金诗歌)_ywyuan_新浪博客

热门文章

  1. 把一棵树转换为二叉树后,这棵二叉树的形态是( )
  2. 微信中无法下载APP h5页面在微信中下载APP的解决方案
  3. 上班可以摸鱼了,刚刚发现在VScode中可玩魂斗罗,超级玛丽,附详细攻略
  4. 作业调度-先来先服务算法
  5. 舜宇光学科技2018年净利润达24.9亿元 同比减少14.2%
  6. 关于museui 使用toast 和Message 插件,图标不显示问题
  7. 语音mos测试软件,TD语音MOS测试方法.ppt
  8. Ventuz学习笔记之-Container预制体等间距排列复制
  9. 商业分析_第五篇 目标群体指数TGI
  10. 一位3A游戏制作高手在ZBrush中雕刻游戏道具心得