bzoj3531: [Sdoi2014]旅行 (树链剖分 && 动态开点线段树)
感觉动态开点线段树空间复杂度好优秀呀
树剖裸题
把每个宗教都开一颗线段树就可以了
但是我一直TLE
然后调了一个小时
为什么呢
因为我 #define max(x, y) (x > y ? x : y)
看起来好像可以减少常数的样子
我也是这么想的(作死
事实上
ans = max(ans, query(x, y))
类似这种语句中
query(x, y)会计算两次
然后就GG了
这告诉我们还是好好用库里的函数吧
#include <cstdio>
#include <algorithm>
#include <vector>
using namespace std;
const int N = + ;
const int M = + ;
#define isdigit(x) (x >= '0' && x <= '9') inline void read(int &ans) {
ans = ;
static char buf = getchar();
register int res = ;
for (; !isdigit(buf); buf = getchar())
if (buf == '-') res = -;
for (; isdigit(buf); buf = getchar())
ans = ans * + buf - '';
ans *= res;
} int tot, n, q;
int sz[N], hs[N], pos[N], fa[N], top[N], w[N], c[N], dep[N];
vector < int > E[N]; void dfs1(int x, int d, int f) {
dep[x] = d; fa[x] = f;
hs[x] = -; sz[x] = ;
int tmp = ;
for (int i = ; i < E[x].size(); i++) {
int u = E[x][i];
if (u == f) continue;
dfs1(u, d + , x);
sz[x] += sz[u];
if (tmp < sz[u])
tmp = sz[u], hs[x] = u;
}
} void dfs2(int x, int t) {
top[x] = t; pos[x] = ++tot;
if (hs[x] == -) return;
dfs2(hs[x], t);
for (int i = ; i < E[x].size(); i++)
if (E[x][i] != fa[x] && E[x][i] != hs[x])
dfs2(E[x][i], E[x][i]);
} int cnt;
int sum[M], maxn[M], ls[M], rs[M], root[N]; inline void pushUp(int o) {
maxn[o] = max(maxn[ls[o]], maxn[rs[o]]);
sum[o] = sum[ls[o]] + sum[rs[o]];
} void modify(int &o, int l, int r, int p, int c) {
if (!o) o = ++cnt;
if (l == r) {
sum[o] = maxn[o] = c;
return ;
}
int mid = l + r >> ;
if (p <= mid) modify(ls[o], l, mid, p, c);
else modify(rs[o], mid + , r, p, c);
pushUp(o);
} int querySum(int o, int l, int r, int L, int R) {
if (!o) return ;
if (l >= L && r <= R) return sum[o];
int mid = l + r >> , ans = ;
if (L <= mid) ans += querySum(ls[o], l, mid, L, R);
if (R > mid) ans += querySum(rs[o], mid + , r, L, R);
return ans;
} inline int querySum(int c, int x, int y) {
int f1 = top[x], f2 = top[y];
int ans = ;
while (f1 != f2) {
if (dep[f1] < dep[f2])
swap(x, y), swap(f1, f2);
ans += querySum(root[c], , n, pos[f1], pos[x]);
x = fa[f1]; f1 = top[x];
}
if (dep[x] > dep[y]) swap(x, y);
ans += querySum(root[c], , n, pos[x], pos[y]);
return ans;
} int queryMax(int o, int l, int r, int L, int R) {
if (!o) return ;
if (l >= L && r <= R) return maxn[o];
int mid = l + r >> , ans = ;
if (L <= mid) ans = max(ans, queryMax(ls[o], l, mid, L, R));
if (R > mid) ans = max(ans, queryMax(rs[o], mid + , r, L, R));
return ans;
} inline int queryMax(int c, int x, int y) {
int f1 = top[x], f2 = top[y];
int ans = ;
while (f1 != f2) {
if (dep[f1] < dep[f2])
swap(x, y), swap(f1, f2);
ans = max(ans, queryMax(root[c], , n, pos[f1], pos[x]));
x = fa[f1]; f1 = top[x];
}
if (dep[x] > dep[y]) swap(x, y);
ans = max(ans, queryMax(root[c], , n, pos[x], pos[y]));
return ans;
} int main() {
read(n); read(q);
for (int i = ; i <= n; i++)
read(w[i]), read(c[i]);
for (int i = ; i < n; i++) {
int u, v;
read(u); read(v);
E[u].push_back(v);
E[v].push_back(u);
}
dfs1(, , ); dfs2(, );
for (int i = ; i <= n; i++)
modify(root[c[i]], , n, pos[i], w[i]);
for (int i = ; i <= q; i++) {
char ch[]; scanf("%s", ch);
int x, y; read(x); read(y);
if (ch[] == 'C') {
if (ch[] == 'C') {
modify(root[c[x]], , n, pos[x], );
c[x] = y;
modify(root[y], , n, pos[x], w[x]);
}
else {
modify(root[c[x]], , n, pos[x], y);
w[x] = y;
}
}
else {
if (ch[] == 'S')
printf("%d\n", querySum(c[x], x, y));
else printf("%d\n", queryMax(c[x], x, y));
}
}
return ;
}
bzoj3531: [Sdoi2014]旅行 (树链剖分 && 动态开点线段树)的更多相关文章
- 【bzoj4999】This Problem Is Too Simple! 树链剖分+动态开点线段树
题目描述 给您一颗树,每个节点有个初始值. 现在支持以下两种操作: 1. C i x(0<=x<2^31) 表示将i节点的值改为x. 2. Q i j x(0<=x<2^31) ...
- BZOJ 3531 [Sdoi2014]旅行 树链剖分+动态开点线段树
题意 S国有N个城市,编号从1到N.城市间用N-1条双向道路连接,满足从一个城市出发可以到达其它所有城市.每个城市信仰不同的宗教,如飞天面条神教.隐形独角兽教.绝地教都是常见的信仰. 为了方便,我们用 ...
- [bzoj 3531][SDOI2014]旅行(树链剖分+动态开点线段树)
题目:http://www.lydsy.com:808/JudgeOnline/problem.php?id=3531 分析: 对于每个颜色(颜色<=10^5)都建立一颗线段树 什么!那么不是M ...
- 洛谷P3313 [SDOI2014]旅行(树链剖分 动态开节点线段树)
题意 题目链接 Sol 树链剖分板子 + 动态开节点线段树板子 #include<bits/stdc++.h> #define Pair pair<int, int> #def ...
- [ZJOI2019]语言(树链剖分+动态开点线段树+启发式合并)
首先,对于从每个点出发的路径,答案一定是过这个点的路径所覆盖的点数.然后可以做树上差分,对每个点记录路径产生总贡献,然后做一个树剖维护,对每个点维护一个动态开点线段树.最后再从根节点开始做一遍dfs, ...
- 【BZOJ3531】[Sdoi2014]旅行 树链剖分+动态开点线段树
[BZOJ3531][Sdoi2014]旅行 Description S国有N个城市,编号从1到N.城市间用N-1条双向道路连接,满足从一个城市出发可以到达其它所有城市.每个城市信仰不同的宗教,如飞天 ...
- bzoj3531——树链剖分+动态开点线段树
3531: [Sdoi2014]旅行 Time Limit: 20 Sec Memory Limit: 512 MB Description S国有N个城市,编号从1到N.城市间用N-1条双向道路连 ...
- BZOJ4999: This Problem Is Too Simple!树链剖分+动态开点线段树
题目大意:将某个节点的颜色变为x,查询i,j路径上多少个颜色为x的点... 其实最开始一看就是主席树+树状数组+DFS序...但是过不去...MLE+TLE BY FCWWW 其实树剖裸的一批...只 ...
- [LuoguU41039]PION后缀自动机 树链剖分+动态开点线段树
链接 刚开始看出题人题解都吓蒙掉了,还以为是什么难题,结果就一板子题 思路:对每一个文件名开一棵线段树,然后树剖即可 #include<bits/stdc++.h> #define REP ...
随机推荐
- 获取指定key对应的node节点信息
需求:之前写的脚本(https://www.cnblogs.com/imdba/p/10197192.html),每个node上都只有一个slot段范围的情况,本次通过测试,实现了,任意段范围的获取方 ...
- C、C++和C#区别概述
译者前言 今天突然好奇C.C++和C#这三门语言都有个C,那么它们之间到底有什么关联呢.所以就去Google了,找到了这篇文章:Understanding the Differences Betwee ...
- Math Magic ZOJ - 3662
核心是要想到只枚举最小公倍数的因子 因为转移过程中一单添加了不是最小公倍数的因子,那么结果必然不合法,虽然最终答案是对的,但是这样的答案根本用不上,反而时间复杂度大大增加 #include<cs ...
- 最简单的githut操作命令
创建SSH Key: 参考:https://blog.csdn.net/weixin_30345055/article/details/95139358 在用户目录下,看看有没有.ssh文件夹,如果有 ...
- python3运行时候报错集锦:读取文件报错
1.关于读取文件报错: 命令执行到cf.read(cfpath),出现如下报错:UnicodeDecodeError: 'gbk' codec can't decode byte 0xa0 in po ...
- Python入门常识【入门必学】
直接上内容: print print 隔行 / 连续 / 间隔输出 print(a) == print(a,end='\n') print(a, end='') print(a, end ...
- java exec python program
I find three methods, the first is using jython, the module of jython can transform the type of data ...
- [Violet]天使玩偶/SJY摆棋子 [cdq分治]
P4169 [Violet]天使玩偶/SJY摆棋子 求离 \((x,y)\) 最近点的距离 距离的定义是 \(|x1-x2|+|y1-y2|\) 直接cdq 4次 考虑左上右上左下右下就可以了-略微卡 ...
- cssflex兼容(横向顶边对齐)
display: flex; display: -webkit-box; display: -moz-box; display: -ms-flexbox; display: -webkit-flex; ...
- H3C ARP配置
一.ARP简介 ARP(Address Resolution Protocol,地址解析协议)是将IP地址解析为以太网MAC地址(或称物理地址)的协议. 在网络中,当主机或其它网络设备有数据要发送给另 ...