BZOJ 3720: Gty的妹子树 [树上size分块]
2017-03-18 20:54
465 查看
传送门
题意: 一棵树,询问子树中权值大于$k$的节点个数,修改点权值,插入新点;强制在线
一开始以为询问多少种不同的权值,那道CF的强制在线带修改版,直接吓哭
然后发现看错了这不一道树上分块水题...
用王室联邦分块的话需要维护每一个块$dfs$序最小值和最大值,并且插入操作会破坏原来的性质
不如直接按$size$分块,根节点$size<block$就加入根,否则新建块
$size$分块不能保证块的数量,可以被菊花图卡掉,然而本题没有所以就可以安心的写了
每个块维护排序后的值
查询操作,不完整的块(因为是$size$分块所以只有子树根所在块不完整)暴力,直接把块建一个图,每个整块二分
修改维护有序,插入也维护有序;当然修改和插入后重新排序也可以
复杂度 修改插入$O(S)$ 查询$O(S+\frac{N}{S}logS)$
题意: 一棵树,询问子树中权值大于$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 ,op,u,x; struct edge{int v,ne;} e[N<<1]; int cnt,h ; 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 , 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 ; 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 =u; int p=pos[u]; if(b[p].size < block) pos =p, b[p].insert(a ); else pos =++m, b[m].push(a ), 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的妹子树 树上分块
- [BZOJ 3720]Gty的妹子树 树上分块
- [BZOJ3720]Gty的妹子树(树上分块)
- [bzoj 3720] Gty的妹子树 (树上分块)
- BZOJ 3731 3731: Gty的超级妹子树 [树上size分块 !]
- Bzoj3720:Gty的妹子树:树分块
- bzoj 3720: Gty的妹子树 树分块
- BZOJ3720 Gty的妹子树 【树分块】
- [bzoj3720]Gty的妹子树【树分块】
- [BZOJ3731]Gty的超级妹子树(树上分块)
- 【bzoj3809】Gty的二逼妹子序列 莫队+分块
- bzoj 3720: Gty的妹子树
- bzoj3720 Gty的妹子树
- 【BZOJ3809/3236】Gty的二逼妹子序列 [Ahoi2013]作业 莫队算法+分块
- 【BZOJ3720】Gty的妹子树 块状树
- 【分块】【树状数组】bzoj3787 Gty的文艺妹子序列
- BZOJ 3720 gty的妹子树
- bzoj3720 gty的妹子树
- [bzoj3720]Gty的妹子树
- bzoj 3787: Gty的文艺妹子序列 分块+树状数组