[bzoj 3720] Gty的妹子树 (树上分块)
树上分块(块状树)
Description
我曾在弦歌之中听过你,
檀板声碎,半出折子戏。
舞榭歌台被风吹去,
岁月深处尚有余音一缕……
Gty神(xian)犇(chong)从来不缺妹子……
他来到了一棵妹子树下,发现每个妹子有一个美丽度……
由于Gty很哲♂学,他只对美丽度大于某个值的妹子感兴趣。
他想知道某个子树中美丽度大于k的妹子个数。
某个妹子的美丽度可能发生变化……
树上可能会出现一只新的妹子……
维护一棵初始有n个节点的有根树(根节点为1),树上节点编号为1-n,每个点有一个权值wi。
支持以下操作:
0 u x 询问以u为根的子树中,严格大于x的值的个数。(u=lastans,x=lastans)
1 u x 把u节点的权值改成x。(u=lastans,x=lastans)
2 u x 添加一个编号为"当前树中节点数+1"的节点,其父节点为u,其权值为x。(u=lastans,x=lastans)
最开始时lastans=0。
Input
输入第一行包括一个正整数n(1<=n<=30000),代表树上的初始节点数。
接下来n-1行,每行2个整数u,v,为树上的一条无向边。
任何时刻,树上的任何权值大于等于0,且两两不同。
接下来1行,包括n个整数wi,表示初始时每个节点的权值。
接下来1行,包括1个整数m(1<=m<=30000),表示操作总数。
接下来m行,每行包括三个整数 op,u,v:
op,u,v的含义见题目描述。
保证题目涉及的所有数在int内。
Output
对每个op=0,输出一行,包括一个整数,意义见题目描述。
Sample Input
2
1 2
10 20
1
0 1 5
Sample Output
2
Solution
这是一道很裸的树上分块题目(又叫块状树)。
我们设一个块的大小为M,对于一个节点,如果它的父亲所属块的大小小于M,则将该点加入其父亲的块,否则将该点加入一个新的块,并建一条从父亲块到新块的边。
在查询u节点为根的子树时,对于和u属于一个块的点暴力枚举,其他点则整块利用二分来计算。对于随机数据,时间复杂度可看做\(O(n * \sqrt{n} * log_n)\) ,可以接受。
Code
#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
#define adde(u, v) (e[ecnt] = (edge){v, head[u]}, head[u] = &e[ecnt++])
#define addbe(u, v) (be[blcnt] = (edge){v, bhead[u]}, bhead[u] = &be[blcnt++])
const int maxn = 3e5 + 10, Block = 200;
int ecnt, bcnt, blcnt;
int w[maxn<<1], fa[maxn<<1], bel[maxn];
struct edge {int v; edge *next;} e[maxn<<2], *head[maxn<<1], be[maxn<<1], *bhead[maxn];
struct BLOCK {
int sz, a[Block];
void sort() {std::sort(a, a + sz);}
int find(int k) {return sz - (upper_bound(a, a + sz, k) - a);}
} B[40000];
void build(int u) {
for(edge *k = head[u]; k; k = k->next) if(fa[u] != k->v) {
int tmp;
if(B[bel[u]].sz < Block) {
tmp = bel[k->v] = bel[u];
B[tmp].a[B[tmp].sz++] = w[k->v];
}
else {
tmp = bel[k->v] = ++bcnt;
B[bcnt].a[B[bcnt].sz++] = w[k->v];
addbe(bel[u], tmp);
}
B[tmp].sort();
fa[k->v] = u;
build(k->v);
}
}
void update(int u, int v) {
int tmp = bel[u], k = lower_bound(B[tmp].a, B[tmp].a + B[tmp].sz, w[u]) - B[tmp].a;
B[tmp].a[k] = v; w[u] = v;
B[tmp].sort();
}
int bdfs(int u, int x) {
int res = B[u].find(x);
for(edge *k = bhead[u]; k; k = k->next) {
res += bdfs(k->v, x);
}
return res;
}
int pdfs(int u, int x) {
int res = 0;
if(w[u] > x) res++;
for(edge *k = head[u]; k; k = k->next) if(k->v != fa[u]) {
if(bel[u] == bel[k->v]) res += pdfs(k->v, x);
else res += bdfs(bel[k->v], x);
}
return res;
}
int query(int u, int k) {
int p, res = 0;
res += pdfs(u, k);
return res;
}
int main() {
int n, m, u, v, last = 0, op;
scanf("%d", &n);
for(int i = 1; i < n; i++) scanf("%d%d", &u, &v), adde(u, v), adde(v, u);
for(int i = 1; i <= n; i++) scanf("%d", &w[i]);
fa[1] = -1, B[++bcnt].sz = 1, B[bcnt].a[0] = w[1], bel[1] = bcnt;
build(1);
scanf("%d", &m);
for(int i = 0; i < m; i++) {
scanf("%d%d%d", &op, &u, &v); u ^= last, v ^= last;
if(op == 0) {
printf("%d\n", last = query(u, v));
}
if(op == 1) {
update(u, v);
}
if(op == 2) {
w[++n] = v;
adde(u, n);
fa[n] = u;
int tmp;
if(B[tmp = bel[u]].sz < Block) B[tmp].a[B[tmp].sz++] = v, bel[n] = bel[u];
else B[tmp = ++bcnt].a[B[tmp].sz++] = v, addbe(bel[u], bcnt), bel[n] = bcnt;
B[tmp].sort();
}
}
return 0;
}
[bzoj 3720] Gty的妹子树 (树上分块)的更多相关文章
- BZOJ 3720: Gty的妹子树 [树上size分块]
传送门 题意: 一棵树,询问子树中权值大于$k$的节点个数,修改点权值,插入新点:强制在线 一开始以为询问多少种不同的权值,那道CF的强制在线带修改版,直接吓哭 然后发现看错了这不一道树上分块水题.. ...
- bzoj 3720: Gty的妹子树 块状树
3720: Gty的妹子树 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 412 Solved: 153[Submit][Status] Descr ...
- bzoj 3720 Gty的妹子树 树分块?瞎搞
Gty的妹子树 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 2149 Solved: 781[Submit][Status][Discuss] D ...
- BZOJ.3720.Gty的妹子树(树分块)
题目链接 洛谷上惨遭爆零是为什么.. 另外这个树分块算法是假的. /* 插入删除只涉及一个数,故每次可以枚举一遍,而不是重构完后sort */ #include<cmath> #inclu ...
- BZOJ 3744: Gty的妹子序列 【分块 + 树状数组 + 主席树】
任意门:https://www.lydsy.com/JudgeOnline/problem.php?id=3744 3744: Gty的妹子序列 Time Limit: 20 Sec Memory ...
- BZOJ3720 Gty的妹子树 询问分块、主席树
传送门 学到了询问分块的科技-- 对于修改操作,每发生了\(S\)次修改就重构整棵树,小于\(S\)次的修改操作丢到一个队列里面. 对于每一次查询操作,先在主席树上查询当前子树内部大于\(k\)的节点 ...
- luogu P2137 Gty的妹子树(分块,主席树)
询问的化我们可以建主席树.然后修改?,树套树...,最后插入?炸了. 所以我们对操作进行分块. 我们先对整棵树建一个主席树.修改,插入我们先记录下来.然后询问的时候先对主席树查询,然后暴力遍历我们记录 ...
- 【BZOJ3720】Gty的妹子树 块状树
[BZOJ3720]Gty的妹子树 我曾在弦歌之中听过你,檀板声碎,半出折子戏.舞榭歌台被风吹去,岁月深处尚有余音一缕……Gty神(xian)犇(chong)从来不缺妹子……他来到了一棵妹子树下,发现 ...
- bzoj 3744: Gty的妹子序列 主席树+分块
3744: Gty的妹子序列 Time Limit: 15 Sec Memory Limit: 128 MBSubmit: 101 Solved: 34[Submit][Status] Descr ...
随机推荐
- R语言table()函数
R语言table()函数比较有用,两个示例尤其是混淆矩阵这个案例比较有用: 例子一:统计频次 z<-c(1,2,2,4,2,7,1,1);z1<-table(z);summary(z1); ...
- Software Engineering | Factory method pattern
工厂对象通常包含一个或多个方法,用来创建这个工厂所能创建的各种类型的对象.这些方法可能接收参数,用来指定对象创建的方式,最后返回创建的对象. 有时,特定类型对象的控制过程比简单地创建一个对象更复杂.在 ...
- Cookie安全与CSRF和XSS攻击知识点收集
个人简单理解: 1.XSS最简单的理解就是可以在表单提交的内容上嵌入JS执行代码,然后页面渲染的时候没有过滤时会自动执行这个脚本. 2.CSRF可以理解为当你登录了京东,浏览器上保存了你登录的Cook ...
- hdu 4300 Clairewd’s message(具体解释,扩展KMP)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4300 Problem Description Clairewd is a member of FBI. ...
- 【转】supervisord使用
Supervisor (http://supervisord.org) 是一个用 Python 写的进程管理工具,可以很方便的用来启动.重启.关闭进程(不仅仅是 Python 进程).除了对单个进程的 ...
- 从SDCard获取的图片按分辨率处理的方法
前段时间公司开发的Launcher要做主题切换的功能,但切换主题时须要从sdcard中获取要切换的图片资源,拿到后图片的大小不正常. 后来查找原因是:系统对不同分辨率拿到的图片资源会自己主动的做转化, ...
- __del__删除方法
class dog: def __del__(self): print("删除机制被调用了...") dog1 = dog() del dog1 #在这里是先删除掉了,所以就去上面 ...
- 爬虫框架_scrapy1
介绍: Scrapy一个开源和协作的框架,其最初是为了页面抓取 (更确切来说, 网络抓取 )所设计的,使用它可以以快速.简单.可扩展的方式从网站中提取所需的数据.但目前Scrapy的用途十分广泛,可用 ...
- SqlServer,Oracle,Mysql 获取指定行数
--sqlserver * FROM dbo.T_TASK --oracle --mysql ,
- MapReduce 1工作原理图文详解
MapReduce工作原理图文详解 一 MapReduce程序执行流程 程序执行流程图如下: 流程分析:1.在客户端启动一个作业.2.向JobTracker请求一个Job ID.3.将运行作业所需要的 ...