首页 > 代码库 > BZOJ 3720: Gty的妹子树 [树上size分块]

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);    }}

 

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