【BZOJ3720】Gty的妹子树 块状树

【BZOJ3720】Gty的妹子树

我曾在弦歌之中听过你,
檀板声碎,半出折子戏。
舞榭歌台被风吹去,
岁月深处尚有余音一缕……
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

题解:这题不是用带插入区间k小值维护DFS序就行吗?然而看discuss发现空间卡得要死,于是赶紧去学又好写又好理解的分块~

怎么做呢?插入时,如果父亲的块大小=B,那么就再开一块,否则就塞到父亲的块里。然后块内按权值排序;查询时,如果x的儿子y与x在同一块中,则暴力查询,否则直接在y的块里二分,然后递归做下去即可。

代码还是挺短的~

P.S:重大错误!由于本人的代码中出现了一些奇奇怪怪的错误,所以遇到菊花的数据会被卡。改进方法:在插入时,记录一下每个点儿子的块中,最后一个块是哪个,即为lastson[]。然后加入时,如果父亲节点所在块已满,则将当前节点加到lastson[fa]的块中。但是这样会导致,一个块中的点可能不连续,所以对于每个点,再开个vector记录它所有儿子的块就好了。

P.P.S:好像还是会被卡的样子。。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <vector>
#include <algorithm>
#include <cmath>
#define lb(A,B) (lower_bound(s[A].begin(),s[A].end(),B,cmp)-s[A].begin())
using namespace std;
const int maxn=60010;
int n,m,tot,B,cnt,CNT,ans;
int fa[maxn],to[maxn<<1],next[maxn<<1],nb[maxn],bel[maxn],head[maxn],v[maxn],siz[maxn],TO[maxn<<1],NEXT[maxn<<1],HEAD[maxn];
vector<int> s[maxn],ch[maxn],cs[maxn];
inline void add(int a,int b)
{
	to[cnt]=b,next[cnt]=head[a],head[a]=cnt++;
}
inline void ADD(int a,int b)
{
	TO[CNT]=b,NEXT[CNT]=HEAD[a],HEAD[a]=CNT++;
}
inline void insert(int x)
{
	if(x==1)
		nb[x]=bel[x]=++tot;
	else	if(siz[nb[fa[x]]]==B)
		nb[fa[x]]=nb[x]=bel[x]=++tot,cs[fa[x]].push_back(tot),ADD(bel[fa[x]],tot);
	else
	{
		if(nb[fa[x]]==bel[fa[x]])	ch[fa[x]].push_back(x);
		nb[x]=bel[x]=nb[fa[x]];
	}
	siz[bel[x]]++,s[bel[x]].push_back(x);
	for(int t=siz[bel[x]]-1;t&&v[s[bel[x]][t-1]]>v[x];t--)	swap(s[bel[x]][t-1],s[bel[x]][t]);
}
void dfs(int x)
{
	insert(x);
	for(int i=head[x];i!=-1;i=next[i])	if(to[i]!=fa[x])	fa[to[i]]=x,dfs(to[i]);
}
bool cmp(const int &a,const int &b)
{
	return v[a]<v[b];
}
void calc(int x,int y)
{
	v[0]=y+1;
	int t=lb(x,0);
	ans+=siz[x]-t;
	for(int i=HEAD[x];i!=-1;i=NEXT[i])	calc(TO[i],y);
}
void query(int x,int y)
{
	ans+=(v[x]>y);
	for(int i=0;i<(int)ch[x].size();i++)	query(ch[x][i],y);
	for(int i=0;i<(int)cs[x].size();i++)	calc(cs[x][i],y);
}
inline int rd()
{
	int ret=0,f=1;	char gc=getchar();
	while(gc<'0'||gc>'9')	{if(gc=='-')f=-f;	gc=getchar();}
	while(gc>='0'&&gc<='9')	ret=ret*10+gc-'0',gc=getchar();
	return ret*f;
}
int main()
{
	n=rd();
	int i,t,a,b,c,op;
	memset(head,-1,sizeof(head)),memset(HEAD,-1,sizeof(HEAD));
	for(i=1;i<n;i++)	a=rd(),b=rd(),add(a,b),add(b,a);
	for(i=1;i<=n;i++)	v[i]=rd();
	m=rd(),B=int(ceil(sqrt(double(n+m))));
	dfs(1);
	for(i=1;i<=m;i++)
	{
		op=rd(),a=rd()^ans,b=rd()^ans;
		if(op==0)
		{
			ans=0;
			query(a,b);
			printf("%d\n",ans);
		}
		if(op==1)
		{
			c=bel[a],t=lb(c,a),v[a]=b;
			for(;t<siz[c]-1&&v[s[c][t+1]]<b;t++)	swap(s[c][t+1],s[c][t]);
			if(t!=siz[c])	for(;t&&v[s[c][t-1]]>b;t--)	swap(s[c][t-1],s[c][t]);
		}
		if(op==2)	v[++n]=b,fa[n]=a,insert(n);
	}
	return 0;
}

 

posted @ 2017-09-13 13:55  CQzhangyu  阅读(377)  评论(0编辑  收藏  举报