题目大意 :
有 n 个城市连成一棵树, 每个城市有两个关键字, 一个是该城市的宗教, 另一个是城市的评级;
旅行者要在城市间旅行, 他只会在和自己宗教相同的城市留宿;
维护四个树上操作 {
1. “CC x c“ :城市 x 的居民全体改信了 c 教;
2. “CW x w“ :城市 x 的评级调整为 w;
3. “QS x y“ :一位旅行者从城市 x 出发,到城市 y,并记下了途中留宿过的城市的评级总和;
4. “QM x y“:一位旅行者从城市 x 出发,到城市 y ,并记下了途中留宿过的城市的评级最大值;
}
(旅行者信的教和旅行的终点相同;

树剖+线段树 : 如果对每种宗教都开一颗线段树, 内存爆炸 -------> 考虑动态开点

动态开点 {
在这道题中, 可以考虑给每一种宗教开一个线段树, 但一开始不需要开满;
对于每一个第一次出现的宗教或者一个宗教里的一个新城市, 都把他当做一个新节点;
对于单次操作 时间复杂度和空间复杂度都是 O(log n) , 因为对于一种宗教最多有n个节点, 在线段树里找到一个节点最多 logn+1 次;
}

代码如下 :

 //Author : 15owzLy1
//luogu3313.cpp
//2018 12 09 14:24:30
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define INF 2100000000
typedef long long ll;
typedef double db;
template<typename T>inline void read(T &_) {
_=;int __=;char ___=getchar();
while(___<''||___>'')__|=(___=='-'),___=getchar();
while(___>=''&&___<='')_=(_<<)+(_<<)+(___^),___=getchar();
_=__?-_:_;
} const int N = (int)1e5+;
struct edge {
int next, to;
}edge[N<<];
int head[N], cnt=, c[N], w[N];
int n, q, hson[N], size[N], dfn[N], front[N], dep[N], fa[N]; class Segment_Tree {
private :
struct node {
int sum, max, l, r;
#define t a[rt]
#define lson a[a[rt].l]
#define rson a[a[rt].r]
}a[N*];
int cnt;
inline void push_up(int rt) {
t.sum=lson.sum+rson.sum;
t.max=std::max(lson.max, rson.max);
}
public :
int root[N];
void update(int &rt, int del, int tl, int tr, int pos) {
if(!rt) rt=++cnt;
if(tl==tr) { t.max=t.sum=del; return ; }
int mid=(tl+tr)>>;
if(mid>=pos) update(t.l, del, tl, mid, pos);
else update(t.r, del, mid+, tr, pos);
push_up(rt);
}
void remove(int &rt, int tl, int tr, int pos) {
if(tl==tr) { rt=t.sum=t.max=; return ; }
int mid=(tl+tr)>>;
if(mid>=pos) remove(t.l, tl, mid, pos);
else remove(t.r, mid+, tr, pos);
push_up(rt);
}
int query_sum(int rt, int l, int r, int tl, int tr) {
if(l<=tl&&tr<=r) return t.sum;
int mid=(tl+tr)>>, ret=;
if(mid>=l) ret+=query_sum(t.l, l, r, tl, mid);
if(mid<r) ret+=query_sum(t.r, l, r, mid+, tr);
return ret;
}
int query_max(int rt, int l, int r, int tl, int tr) {
if(l<=tl&&tr<=r) return t.max;
int mid=(tl+tr)>>, ret=;
if(mid>=l) ret=std::max(ret, query_max(t.l, l, r, tl, mid));
if(mid<r) ret=std::max(ret, query_max(t.r, l, r, mid+, tr));
return ret;
}
}T; inline void jb(int u, int v) {
edge[++cnt].to=v;
edge[cnt].next=head[u];
head[u]=cnt;
} void get_hson(int u) {
size[u]=;
for(int i=head[u];i;i=edge[i].next) {
int v=edge[i].to;
if(v==fa[u]) continue;
fa[v]=u, dep[v]=dep[u]+;
get_hson(v);
size[u]+=size[v];
if(size[v]>=size[hson[u]]) hson[u]=v;
}
} void get_front(int u, int father) {
dfn[u]=++dfn[], front[u]=father;
if(hson[u]) get_front(hson[u], father);
for(int i=head[u];i;i=edge[i].next) {
int v=edge[i].to;
if(v==fa[u]||v==hson[u]) continue;
get_front(v, v);
}
} inline int query_sum(int u, int v) {
int ret=, cl=c[v];
while(front[u]!=front[v]) {
if(dep[front[u]]>dep[front[v]]) std::swap(u, v);
ret+=T.query_sum(T.root[cl], dfn[front[v]], dfn[v], , n);
v=fa[front[v]];
}
if(dep[u]>dep[v]) std::swap(u, v);
ret+=T.query_sum(T.root[cl], dfn[u], dfn[v], , n);
return ret;
} inline int query_max(int u, int v) {
int ret=, cl=c[v];
while(front[u]!=front[v]) {
if(dep[front[u]]>dep[front[v]]) std::swap(u, v);
ret=std::max(ret, T.query_max(T.root[cl], dfn[front[v]], dfn[v], , n));
v=fa[front[v]];
}
if(dep[u]>dep[v]) std::swap(u, v);
ret=std::max(ret, T.query_max(T.root[cl], dfn[u], dfn[v], , n));
return ret;
} int main() {
#ifndef ONLINE_JUDGE
freopen("luogu3313.in","r",stdin);
freopen("luogu3313.out","w",stdout);
#endif
char opt[];
int x, y;
read(n), read(q);
for(int i=;i<=n;i++) read(w[i]), read(c[i]);
for(int i=;i<n;i++) read(x), read(y), jb(x, y), jb(y, x);
get_hson(); get_front(, );
for(int i=;i<=n;i++)
T.update(T.root[c[i]], w[i], , n, dfn[i]); while(q--) {
scanf("%s", opt);
read(x), read(y);
if(opt[]=='C') {
//change C change W
if(opt[]=='C') {
T.remove(T.root[c[x]], , n, dfn[x]);
c[x]=y;
T.update(T.root[c[x]], w[x], , n, dfn[x]);
}
else T.update(T.root[c[x]], y, , n, dfn[x]), w[x]=y;
}
else {
//query S query W
if(opt[]=='S') printf("%d\n", query_sum(x, y));
else printf("%d\n", query_max(x, y));
}
}
return ;
}

「luogu3313」[SDOI2014] 旅行的更多相关文章

  1. Loj #3057. 「HNOI2019」校园旅行

    Loj #3057. 「HNOI2019」校园旅行 某学校的每个建筑都有一个独特的编号.一天你在校园里无聊,决定在校园内随意地漫步. 你已经在校园里呆过一段时间,对校园内每个建筑的编号非常熟悉,于是你 ...

  2. @loj - 2987@ 「CTSC2016」时空旅行

    目录 @description@ @solution@ @accepted code@ @details@ @description@ 2045 年,人类的技术突飞猛进,已经找到了进行时空旅行的方法. ...

  3. LOJ 3057 「HNOI2019」校园旅行——BFS+图等价转化

    题目:https://loj.ac/problem/3057 想令 b[ i ][ j ] 表示两点是否可行,从可行的点对扩展.但不知道顺序,所以写了卡时间做数次 m2 迭代的算法,就是每次遍历所有不 ...

  4. 「loj3057」「hnoi2019」校园旅行

    题目 一个n个点m条边的无向图,每个点有0 / 1 的标号; 有q个询问,每次询问(u,v)直接是否存在回文路径(可以经过重复的点和边); $1 \le n \le 5 \times 10^3  , ...

  5. 【LOJ2604】「NOIP2012」开车旅行

    [题目链接] [点击打开链接] [题目大意] 从西到东的坐标轴\([1,n]\)上有\(n\)个海拔互不相同的城市,每两个城市之间的距离定义为\(dis(i,j)=|h_i-h_j|\) 小\(A\) ...

  6. 「NOIP2012」开车旅行

    传送门 Luogu 解题思路 第一步预处理每个点后面的最近点和次近点,然后就是模拟题意. 但是如果就这么搞是 \(O(N^2)\) 的,不过可以过70分,考场上也已经比较可观了. 考虑优化. 预处理最 ...

  7. 「JSOI2013」旅行时的困惑

    「JSOI2013」旅行时的困惑 传送门 由于我们的图不仅是一个 \(\text{DAG}\) 而且在形态上还是一棵树,也就是说我们为了实现节点之间互相可达,就必须把每条边都覆盖一次,因为两个点之间的 ...

  8. 「JSOI2010」旅行

    「JSOI2010」旅行 传送门 比较妙的一道 \(\text{DP}\) 题,思维瓶颈应该就是如何确定状态. 首先将边按边权排序. 如果我们用 \(01\) 串来表示 \(m\) 条边是否在路径上, ...

  9. 「案例」让房东在 Airbnb 上展示他们的热情好客

    如何才能让房东准确的描述自己的房源,如何才能让房东充分的展示自己的房源.Airbnb 在这次更新里尝试去解决了这两个问题,让我们跟随作者的文笔去了解一下整个项目的经过. 关于本文 原文作者:Cecil ...

随机推荐

  1. (五)Cluster Health

    Let’s start with a basic health check, which we can use to see how our cluster is doing. We’ll be us ...

  2. spring boot 2.0 WebMvcConfigurerAdapter过时解决方法

    第一种: @Configuration public class WebAppConfig implements WebMvcConfigurer{ @Bean public HandlerInter ...

  3. loss函数和cost函数

    loss函数指单个样本的预测值和真值的偏差 cost函数指整体样本的预测值和真值的偏差

  4. go笔记-熔断器

    参考: https://studygolang.com/articles/13254 区别:(限速器 VS 熔断器) 限速器(limiter)可以限制接口自身被调的频率 熔断器可监控所调用的服务的失败 ...

  5. DisplayAttribute没作用,why?

    namespace WebBulletinBoard.DataAccess { using System; using System.ComponentModel.DataAnnotations; u ...

  6. 【Swift 3.0】iOS 国际化切换语言

    有的 App 可能有切换语言的选项,结合系统自动切换最简单的办法: fileprivate var localizedBundle: Bundle = { return Bundle(path: Bu ...

  7. Linux下redis的安装及配置

    1.去官网下载redis(redis.io) 2.将其解压到根目录下 3.进入解压的目录,然后编译源程序, 如果不是root账户登录的,命令前面需要加sudo make make install PR ...

  8. jmeter学习记录--08--第三方测试组件

    我们安装的JMeter版本,功能仍然有欠缺,插件是一种补充,官方提供了很多插件. 官网地址:http://www.jmeter-plugins.org/, 里面有很多可以安装到JMeter的插件,基本 ...

  9. 数据库优化-mysql中INNODB和MYIASM引擎的区别

    Innodb引擎 Innodb引擎提供了对数据库ACID事务的支持,并且实现了SQL标准的四种隔离级别. 该引擎还提供了行级锁和外键约束,它的设计目标是处理大容量数据库系统,它本身其实就是基于MySQ ...

  10. Python——Django-__init__.py的内容

    一.告诉Django用pymysql来代替默认的MySQLdb(在__init__.py里) import pymysql #告诉Django用pymysql来代替默认的MySQLdb pymysql ...