题目大意 :
有 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. (二)Basic Concepts 基本概念

    Basic Concepts There are a few concepts that are core to Elasticsearch. Understanding these concepts ...

  2. python处理Windows平台上路径有空格

    最近在采集windows上中间件的时候,遇到了文件路径有空格的问题. 例如:Aapche的安装路径为D:\Program Files\Apache Software Foundation\Apache ...

  3. 解决刷新页面vuex store中数据丢失的问题

    **问题背景:**页面刷新后,vuex中的数据丢失.这是因为:js代码是运行在内存中的,代码运行时的所有变量.函数也都是保存在内存中的.进行刷新页面的操作,以前申请的内存被释放,重新加载脚本代码,变量 ...

  4. CKEditor 4.5 filetools, XHR.withCredentials = true,

    var editor = CKEDITOR.replace( 'editor1', { extraPlugins: 'uploadimage,filetools', imageUploadUrl: ' ...

  5. sql-josn

    1 select fname,fdistrict ,famount from sale for json auto---最简单方式[{"name":"name1" ...

  6. Flask上下文管理、session原理和全局g对象

    一.一些python的知识 1.偏函数 def add(x, y, z): print(x + y + z) # 原本的写法:x,y,z可以传任意数字 add(1,2,3) # 如果我要实现一个功能, ...

  7. python常用函数用法整理

    1,zeros函数(同理的还有ones函数) http://www.jb51.net/article/127649.htm 注意: (m,n)是生成m行n列的矩阵,但要生成二维矩阵的时候要用两层括号, ...

  8. jzoj6101. 【GDOI2019模拟2019.4.2】Path

    题目链接:https://jzoj.net/senior/#main/show/6101 记\(f_i\)为从\(i\)号点走到\(n\)号点所花天数的期望 那么根据\(m\)条边等可能的出现一条和一 ...

  9. node.js的基础知识

    第一部分知识: .命令行窗口(小黑屏).CMD窗口.终端.shell - 开始菜单 --> 运行 --> CMD --> 回车 - 常用的指令: dir 列出当前目录下的所有文件 c ...

  10. 2017-12-19python全栈9期第四天第二节之列表的增删查改之删除的pop和del和remove和clear

    #!/user/bin/python# -*- coding:utf-8 -*-li = ['zs','ls','ww','zl']# name = li.pop(1) #按索引位置删除有返回值# n ...