树上分块(块状树)


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的妹子树 (树上分块)的更多相关文章

  1. BZOJ 3720: Gty的妹子树 [树上size分块]

    传送门 题意: 一棵树,询问子树中权值大于$k$的节点个数,修改点权值,插入新点:强制在线 一开始以为询问多少种不同的权值,那道CF的强制在线带修改版,直接吓哭 然后发现看错了这不一道树上分块水题.. ...

  2. bzoj 3720: Gty的妹子树 块状树

    3720: Gty的妹子树 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 412  Solved: 153[Submit][Status] Descr ...

  3. bzoj 3720 Gty的妹子树 树分块?瞎搞

    Gty的妹子树 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 2149  Solved: 781[Submit][Status][Discuss] D ...

  4. BZOJ.3720.Gty的妹子树(树分块)

    题目链接 洛谷上惨遭爆零是为什么.. 另外这个树分块算法是假的. /* 插入删除只涉及一个数,故每次可以枚举一遍,而不是重构完后sort */ #include<cmath> #inclu ...

  5. BZOJ 3744: Gty的妹子序列 【分块 + 树状数组 + 主席树】

    任意门:https://www.lydsy.com/JudgeOnline/problem.php?id=3744 3744: Gty的妹子序列 Time Limit: 20 Sec  Memory ...

  6. BZOJ3720 Gty的妹子树 询问分块、主席树

    传送门 学到了询问分块的科技-- 对于修改操作,每发生了\(S\)次修改就重构整棵树,小于\(S\)次的修改操作丢到一个队列里面. 对于每一次查询操作,先在主席树上查询当前子树内部大于\(k\)的节点 ...

  7. luogu P2137 Gty的妹子树(分块,主席树)

    询问的化我们可以建主席树.然后修改?,树套树...,最后插入?炸了. 所以我们对操作进行分块. 我们先对整棵树建一个主席树.修改,插入我们先记录下来.然后询问的时候先对主席树查询,然后暴力遍历我们记录 ...

  8. 【BZOJ3720】Gty的妹子树 块状树

    [BZOJ3720]Gty的妹子树 我曾在弦歌之中听过你,檀板声碎,半出折子戏.舞榭歌台被风吹去,岁月深处尚有余音一缕……Gty神(xian)犇(chong)从来不缺妹子……他来到了一棵妹子树下,发现 ...

  9. bzoj 3744: Gty的妹子序列 主席树+分块

    3744: Gty的妹子序列 Time Limit: 15 Sec  Memory Limit: 128 MBSubmit: 101  Solved: 34[Submit][Status] Descr ...

随机推荐

  1. R语言table()函数

    R语言table()函数比较有用,两个示例尤其是混淆矩阵这个案例比较有用: 例子一:统计频次 z<-c(1,2,2,4,2,7,1,1);z1<-table(z);summary(z1); ...

  2. Software Engineering | Factory method pattern

    工厂对象通常包含一个或多个方法,用来创建这个工厂所能创建的各种类型的对象.这些方法可能接收参数,用来指定对象创建的方式,最后返回创建的对象. 有时,特定类型对象的控制过程比简单地创建一个对象更复杂.在 ...

  3. Cookie安全与CSRF和XSS攻击知识点收集

    个人简单理解: 1.XSS最简单的理解就是可以在表单提交的内容上嵌入JS执行代码,然后页面渲染的时候没有过滤时会自动执行这个脚本. 2.CSRF可以理解为当你登录了京东,浏览器上保存了你登录的Cook ...

  4. hdu 4300 Clairewd’s message(具体解释,扩展KMP)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4300 Problem Description Clairewd is a member of FBI. ...

  5. 【转】supervisord使用

    Supervisor (http://supervisord.org) 是一个用 Python 写的进程管理工具,可以很方便的用来启动.重启.关闭进程(不仅仅是 Python 进程).除了对单个进程的 ...

  6. 从SDCard获取的图片按分辨率处理的方法

    前段时间公司开发的Launcher要做主题切换的功能,但切换主题时须要从sdcard中获取要切换的图片资源,拿到后图片的大小不正常. 后来查找原因是:系统对不同分辨率拿到的图片资源会自己主动的做转化, ...

  7. __del__删除方法

    class dog: def __del__(self): print("删除机制被调用了...") dog1 = dog() del dog1 #在这里是先删除掉了,所以就去上面 ...

  8. 爬虫框架_scrapy1

    介绍: Scrapy一个开源和协作的框架,其最初是为了页面抓取 (更确切来说, 网络抓取 )所设计的,使用它可以以快速.简单.可扩展的方式从网站中提取所需的数据.但目前Scrapy的用途十分广泛,可用 ...

  9. SqlServer,Oracle,Mysql 获取指定行数

    --sqlserver * FROM dbo.T_TASK --oracle --mysql ,

  10. MapReduce 1工作原理图文详解

    MapReduce工作原理图文详解 一 MapReduce程序执行流程 程序执行流程图如下: 流程分析:1.在客户端启动一个作业.2.向JobTracker请求一个Job ID.3.将运行作业所需要的 ...