码迷,mamicode.com
首页 > 其他好文 > 详细

【BZOJ3720】Gty的妹子树 块状树

时间:2017-09-13 15:10:15      阅读:175      评论:0      收藏:0      [点我收藏+]

标签:get   节点   span   操作   bool   sample   stream   dfs   pen   

【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的块里二分,然后递归做下去即可。

代码还是挺短的~

#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],head[maxn],bel[maxn],v[maxn],siz[maxn],TO[maxn<<1],NEXT[maxn<<1],HEAD[maxn];
vector<int> s[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++;
}
void dfs(int x)
{
	if(x==1||siz[bel[fa[x]]]==B)	bel[x]=++tot,ADD(bel[fa[x]],bel[x]);
	else	bel[x]=bel[fa[x]];
	siz[bel[x]]++,s[bel[x]].push_back(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=head[x];i!=-1;i=next[i])	if(to[i]!=fa[x])
	{
		if(bel[to[i]]==bel[x])	query(to[i],y);
		else	calc(bel[to[i]],y);
	}
}
inline void insert(int x,int y)
{
	if(siz[bel[x]]==B)	bel[y]=++tot,ADD(bel[x],bel[y]);
	else	bel[y]=bel[x];
	add(x,y),fa[y]=x,x=bel[y],siz[x]++,s[x].push_back(y);
	for(int t=siz[x]-1;t&&v[s[x][t-1]]>v[y];t--)	swap(s[x][t-1],s[x][t]);
}
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()
{
	//freopen("bz3720.in","r",stdin);
	n=rd(),B=int(ceil(2*sqrt(double(n))));
	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);
	dfs(1);
	for(i=1;i<=n;i++)	v[i]=rd();
	for(i=1;i<=tot;i++)	sort(s[i].begin(),s[i].end(),cmp);
	m=rd();
	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]);
			for(;t&&v[s[c][t-1]]>b;t--)	swap(s[c][t-1],s[c][t]);
		}
		if(op==2)	v[++n]=b,insert(a,n);
	}
	return 0;
}

【BZOJ3720】Gty的妹子树 块状树

标签:get   节点   span   操作   bool   sample   stream   dfs   pen   

原文地址:http://www.cnblogs.com/CQzhangyu/p/7514566.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!