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

传送门

题意: 一棵树,询问子树中权值大于$k$的节点个数,修改点权值,插入新点;强制在线



一开始以为询问多少种不同的权值,那道CF的强制在线带修改版,直接吓哭

然后发现看错了这不一道树上分块水题...

用王室联邦分块的话需要维护每一个块$dfs$序最小值和最大值,并且插入操作会破坏原来的性质

不如直接按$size$分块,根节点$size<block$就加入根,否则新建块

$size$分块不能保证块的数量,可以被菊花图卡掉,然而本题没有所以就可以安心的写了

每个块维护排序后的值

查询操作,不完整的块(因为是$size$分块所以只有子树根所在块不完整)暴力,直接把块建一个图,每个整块二分

修改维护有序,插入也维护有序;当然修改和插入后重新排序也可以

复杂度 修改插入$O(S)$ 查询$O(S+\frac{N}{S}logS)$

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
typedef long long ll;
const int N=6e4+5, M=1e4+5, S=700;
inline int read(){
    char c=getchar();int x=0,f=1;
    while(c<‘0‘||c>‘9‘){if(c==‘-‘)f=-1;c=getchar();}
    while(c>=‘0‘&&c<=‘9‘){x=x*10+c-‘0‘;c=getchar();}
    return x*f;
}

int n,Q,a[N],op,u,x;
struct edge{int v,ne;} e[N<<1];
int cnt,h[N];
inline void ins(int u,int v) {
    e[++cnt]=(edge){v,h[u]}; h[u]=cnt;
    e[++cnt]=(edge){u,h[v]}; h[v]=cnt;
}

struct meow{
    int a[S], size;
    inline void set() {sort(a+1, a+1+size);}
    inline int count(int v) {return size - (upper_bound(a+1, a+1+size, v) - a) + 1;}
    inline void push(int v) {a[++size]=v;}
    inline void replace(int x,int v) {
        if(x==v) return;
        for(int i=1;i<=size;i++) if(a[i]==x) {
            if(v>x) while(i<size && v>a[i+1]) a[i]=a[i+1], i++;
            else while(i>1 && v<a[i-1]) a[i]=a[i-1], i--;
            a[i]=v; break;
        }
    }
    inline void insert(int v){
        int i;
        for(i=1; i<=size && a[i]<v; i++) ;
        for(int j=size; j>=i; j--) a[j+1]=a[j];
        a[i]=v; size++;
    }
}b[M];
int m, pos[N], block;

struct Graph4Block{
    struct edge{int v,ne;} e[M];
    int cnt,h[M];
    inline void ins(int u,int v) {
        e[++cnt]=(edge){v,h[u]}; h[u]=cnt;
    }
    int dfs(int u,int k) {
        int ans= b[u].count(k);
        for(int i=h[u];i;i=e[i].ne) ans+=dfs(e[i].v, k);
        return ans;
    }
}G;

int fa[N];
void dfs(int u) {
    int p=pos[u];
    b[p].push(a[u]);
    for(int i=h[u];i;i=e[i].ne)
        if(e[i].v!=fa[u]) {
            fa[e[i].v]=u;
            if(b[p].size < block) pos[e[i].v]=p;
            else pos[e[i].v]=++m, G.ins(p, m);
            dfs(e[i].v);
        }
}

struct Block{
    int dfs(int u,int k) {
        int ans= a[u]>k;
        for(int i=h[u];i;i=e[i].ne)
            if(e[i].v!=fa[u]) {
                if(pos[e[i].v] == pos[u]) ans+= dfs(e[i].v, k);
                else ans+= G.dfs(pos[e[i].v], k);
            }
        return ans;
    }
    int Que(int u, int k) {return dfs(u, k);}

    void Cha(int u, int d) {b[pos[u]].replace(a[u], d); a[u]=d;}

    void Ins(int u, int d){
        a[++n]=d; ins(u, n); fa[n]=u;
        int p=pos[u];
        if(b[p].size < block) pos[n]=p, b[p].insert(a[n]);
        else pos[n]=++m, b[m].push(a[n]), G.ins(p, m);
    }
}B;
int main() {
    freopen("in", "r", stdin);
    n=read();
    for(int i=1;i<n;i++) ins(read(), read() );
    for(int i=1;i<=n;i++) a[i]=read();
    block=pow(n, 0.6);
    pos[1]=++m; dfs(1);
    for(int i=1;i<=m;i++) b[i].set();

    Q=read(); int lastans=0;
    for(int i=1;i<=Q;i++) {
        op=read();
        u=read()^lastans; x=read()^lastans;
        if(op==0) lastans=B.Que(u, x), printf("%d\n",lastans);
        else if(op==1) B.Cha(u, x);
        else B.Ins(u, x);
    }
}
时间: 2024-12-22 10:48:41

BZOJ 3720: Gty的妹子树 [树上size分块]的相关文章

BZOJ 3720 Gty的妹子树 树上分块

题目大意:给出一棵树,要求维护:1.求出以x为根节点的子树的严格大于y的数量. 2.将一个节点的权值改变. 3.在一个节点下加一个权值为y的节点. 思路:分块这个东西太神了(别找我分析时间复杂度..树上的分块更神... 首先,分块的原则和正常分块一样,把一棵树分成√n块,每一块不超过√n个,然后所有的时间复杂度降到了O(√n),(这个题还有个排序,所以还有一个log(n)). 如何在树上分块.规定根节点在编号为1的块中,然后做一次深搜,如果遍历到的一个节点的时候当前节点所在的块的数量已经达到最大

BZOJ 3731 3731: Gty的超级妹子树 [树上size分块 !]

传送门 题意:一棵树,询问子树中权值大于k的节点个数,修改点权值,插入新点,断开边:强制在线 该死该死该死!!!!!! MD我想早睡觉你知不知道 该死该死沙比提 断开边只会影响一个块,重构这个块就行了 如果断开的点$u$是这个块$p$的根,只修改原图和块图就好了 否则,把$u$子树在块中的部分从$p$里删除,放到一个新块里.并且,这些点连到的其他块的点,也要在块图上与$p$断开与新块相连 所以我们维护一个删除边的$mark$标记 WA:一开始原图加的是双向边,通过判断$fa$防止出错..后来$f

BZOJ 3720 Gty的妹子树 块状树

题目大意:维护一棵树,每个点有一个权值,提供下列操作: 1.询问某棵子树中有多少个节点的权值大于x 2.修改某个节点的权值 3.增加一个叶子节点 强制在线 传说中的树分块 首先DFS,对于每个节点,如果这个节点的父亲节点所在块未满,就塞进父节点所在块中,否则自成一块,然后与父节点所在的块连边 添加节点同理 然后就按照分块直接搞吧0.0 细节实在是太多了 所以写挂的地方看看本蒟蒻的代码就好了0.0 #include <cmath> #include <cstdio> #include

【BZOJ3720】Gty的妹子树 块状树

[BZOJ3720]Gty的妹子树 我曾在弦歌之中听过你,檀板声碎,半出折子戏.舞榭歌台被风吹去,岁月深处尚有余音一缕……Gty神(xian)犇(chong)从来不缺妹子……他来到了一棵妹子树下,发现每个妹子有一个美丽度……由于Gty很哲♂学,他只对美丽度大于某个值的妹子感兴趣.他想知道某个子树中美丽度大于k的妹子个数.某个妹子的美丽度可能发生变化……树上可能会出现一只新的妹子……维护一棵初始有n个节点的有根树(根节点为1),树上节点编号为1-n,每个点有一个权值wi.支持以下操作:0 u x 

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

3744: Gty的妹子序列 Time Limit: 15 Sec  Memory Limit: 128 MBSubmit: 101  Solved: 34[Submit][Status] Description 我早已习惯你不在身边, 人间四月天 寂寞断了弦. 回望身后蓝天, 跟再见说再见…… 某天,蒟蒻Autumn发现了从 Gty的妹子树(bzoj3720) 上掉落下来了许多妹子,他发现 她们排成了一个序列,每个妹子有一个美丽度. Bakser神犇与他打算研究一下这个妹子序列,于是Bakse

BZOJ 3720: Gty的妹子树

3720: Gty的妹子树 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1493  Solved: 502[Submit][Status][Discuss] Description 我曾在弦歌之中听过你, 檀板声碎,半出折子戏. 舞榭歌台被风吹去, 岁月深处尚有余音一缕…… Gty神(xian)犇(chong)从来不缺妹子…… 他来到了一棵妹子树下,发现每个妹子有一个美丽度…… 由于Gty很哲♂学,他只对美丽度大于某个值的妹子感兴趣. 他想知道

BZOJ 3744: Gty的妹子序列

3744: Gty的妹子序列 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 1335  Solved: 379[Submit][Status][Discuss] Description 我早已习惯你不在身边, 人间四月天 寂寞断了弦. 回望身后蓝天, 跟再见说再见…… 某天,蒟蒻Autumn发现了从 Gty的妹子树(bzoj3720) 上掉落下来了许多妹子,他发现 她们排成了一个序列,每个妹子有一个美丽度. Bakser神犇与他打算研究一下这个妹

[BZOJ 720][JZYZOJ 2016]gty的妹子树 强制在线 树分块/树套树

jzyzoj的p2016 先码着,强制在线的树分块或者树套树?关键是我树分块还在入门阶段树套树完全不会啊摔 http://blog.csdn.net/jiangyuze831/article/details/41445003 果然我除了抄代码什么也不会......树分块之类的东西完全不会计算复杂度..... 似乎upper_bound非常浪费时间..所以更改的时候直接循环查找不然会超时...... static这种东西不要胡乱用......如果在后面直接赋值会赋值不上........ 看代码就能

BZOJ3720 Gty的妹子树 【树分块】

题目 我曾在弦歌之中听过你, 檀板声碎,半出折子戏. 舞榭歌台被风吹去, 岁月深处尚有余音一缕-- Gty神(xian)犇(chong)从来不缺妹子-- 他来到了一棵妹子树下,发现每个妹子有一个美丽度-- 由于Gty很哲♂学,他只对美丽度大于某个值的妹子感兴趣. 他想知道某个子树中美丽度大于k的妹子个数. 某个妹子的美丽度可能发生变化-- 树上可能会出现一只新的妹子-- 维护一棵初始有n个节点的有根树(根节点为1),树上节点编号为1-n,每个点有一个权值wi. 支持以下操作: 0 u x 询问以