问题概述:
一棵n个节点的树,每个节点都有一个权值,之后三种操作:
①0 u v查询以u点为根的子树中权值大于v的有多少个
②1 u v表示将u点的权值修改为v
③2 u v表示新建一个节点,编号为节点个数+1,挂在节点u上面,权值为v
强制在线,所有操作中的u和v异或上一次的答案
块状树其实就是将树分块
分块方法:DFS,对于当前节点,如果这个节点的父亲所在块还没有满,就将这个点归入父亲所在块中,否则新建一个块,然后父亲所在的块和这个新建的块连一条边,最后可以形成一棵块状树(默认块大小sqrt(n))
对于这道题,先进行树分块,每个块存一个序列,这个序列就是块中所有点的权值从小到大排列形成
①查询操作0 u v:和u点在一个块里的点直接爆搜,因为点数不超过sqrt(n),所以复杂度就是O(sqrt(n)),而u点子树中所有属于其他块的点,就可以直接在块里二分了,复杂度O(sqrt(n)logn)
②修改操作1 u v:修改它所在块的序列,可以直接暴力重新排序,复杂度O(sqrt(n)log(sqrt(n)))
③加点操作2 u v:和建树的过程一样,判断这个点的父亲u所在块有没有满,有就加入并更新(还是暴力重新序),没有就新建
其实在极大部分情况,每个块的大小都差不多sqrt(n)左右,但是最差情况每个块的大小甚至只有1,也就是说会有n块,这个时候复杂度会降为O(n²)甚至更高,所以这个方法还是慎用
3720: Gty的妹子树
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 1863 Solved: 640
[ Submit][ Status][ Discuss]
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
Sample Output
这题就是上面那个例子
#include<stdio.h>
#include<math.h>
#include<vector>
#include<algorithm>
using namespace std;
vector<int> G[60005], C[5000];
int B, cnt, val[60005], fa[60005], bel[60005], c[5000][5000], h[5000];
void Sech(int u, int p)
{
int i, v, now;
fa[u] = p;
if(u!=1 && h[bel[p]]>=B)
{
now = ++cnt;
C[bel[p]].push_back(now);
}
else
now = bel[p];
if(u!=1)
{
h[now]++, c[now][h[now]] = val[u];
bel[u] = now;
}
for(i=0;i<G[u].size();i++)
{
v = G[u][i];
if(v==p)
continue;
Sech(v, u);
}
}
int SechC(int u, int now)
{
int i, v, ans;
ans = c[u]+h[u]+1-upper_bound(c[u]+1, c[u]+h[u]+1, now);
for(i=0;i<C[u].size();i++)
{
v = C[u][i];
ans += SechC(v, now);
}
return ans;
}
int La(int u, int now)
{
int i, v, ans;
ans = 0;
if(val[u]>now)
ans++;
for(i=0;i<G[u].size();i++)
{
v = G[u][i];
if(v==fa[u])
continue;
if(bel[v]==bel[u])
ans += La(v, now);
else
ans += SechC(bel[v], now);
}
return ans;
}
int main(void)
{
int n, i, x, now, y, ans, opt, Q;
scanf("%d", &n);
B = sqrt(n+30000)+1;
for(i=1;i<=n-1;i++)
{
scanf("%d%d", &x, &y);
G[x].push_back(y);
G[y].push_back(x);
}
for(i=1;i<=n;i++)
scanf("%d", &val[i]);
cnt = bel[1] = h[1] = 1;
c[1][1] = val[1];
Sech(1, 0);
for(i=1;i<=cnt;i++)
sort(c[i]+1, c[i]+h[i]+1);
ans = 0;
scanf("%d", &Q);
while(Q--)
{
scanf("%d%d%d", &opt, &x, &y);
x ^= ans, y ^= ans;
if(opt==0)
{
ans = La(x, y);
printf("%d\n", ans);
}
else if(opt==1)
{
now = bel[x];
c[now][lower_bound(c[now]+1, c[now]+h[now]+1, val[x])-c[now]] = y;
sort(c[now]+1, c[now]+h[now]+1);
val[x] = y;
}
else
{
n += 1;
val[n] = y;
fa[n] = x;
G[n].push_back(x);
G[x].push_back(n);
if(h[bel[x]]>=B)
{
now = ++cnt;
C[bel[x]].push_back(now);
}
else
now = bel[x];
h[now]++, c[now][h[now]] = val[n];
bel[n] = now;
sort(c[now]+1, c[now]+h[now]+1);
}
}
return 0;
}