Description
我曾在弦歌之中听过你,
檀板声碎,半出折子戏。
舞榭歌台被风吹去,
岁月深处尚有余音一缕……
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
1 2
10 20
1
0 1 5
Sample Output
正解:块状树
解题报告:
遥遥昨天讲了许多神奇的数据结构,比如这道题用的块状树,个人感觉就是在树上分块。。。
大概讲一下块状树的思想和用法吧。考虑我们将树上的某一些点变成一个连通块,然后每个块中分别处理(内部都是暴力处理),如果碰到可以整块处理的就整块处理。
每个块都记录一下块内的权值,按顺序排列。块与块之间有连边。
感觉跟分块真的很像。。。第一遍DFS的时候看一下父亲所在的块是否已经满了(设置为块的上限,在根号左右最佳),如果满了的话就新建一个块,并且把新建的块与父亲所在的块连边,否则加入父亲所在的块。每次插入,在块内部都是暴力处理。修改操作也是在块内暴力处理,修改完之后暴力移动,保证有序性。新的插入也是一样的,与第一遍DFS相同,只需看一下父亲所在块是不是满了。查询的话就DFS,发现儿子结点与自己所在块不同,就直接访问整个块,二分查找块内大于需查询的值的个数。
这道题有很多细节要注意,调了一个多小时,中间经历了WA、RE、TLE、MLE,也是醉了。
1 //It is made by jump~ 2 #include <iostream> 3 #include <cstdlib> 4 #include <cstring> 5 #include <cstdio> 6 #include <cmath> 7 #include <algorithm> 8 #include <ctime> 9 #include <vector> 10 #include <queue> 11 #include <map> 12 #include <set> 13 #ifdef WIN32 14 #define OT "%I64d" 15 #else 16 #define OT "%lld" 17 #endif 18 using namespace std; 19 typedef long long LL; 20 const int MAXN = 60011; 21 const int S = 400; //实验表明,400附近最合适。。。 22 int n,ecnt,cnt; 23 int w[MAXN],father[MAXN]; 24 int first[MAXN],next[MAXN*2],to[MAXN*2]; 25 int ans,m; 26 int belong[MAXN]; 27 int head[MAXN]; 28 29 inline int getint() 30 { 31 int w=0,q=0; 32 char c=getchar(); 33 while((c<'0' || c>'9') && c!='-') c=getchar(); 34 if (c=='-') q=1, c=getchar(); 35 while (c>='0' && c<='9') w=w*10+c-'0', c=getchar(); 36 return q ? -w : w; 37 } 38 39 struct kuai_tree{ 40 int size; int a[S+12]; 41 42 inline void insert(int x){//块内暴力插入新元素 43 size++; int i=size; 44 for(;i>=2;i--) if(a[i-1]>x) a[i]=a[i-1]; else break; 45 a[i]=x; 46 } 47 48 inline int zuo_ask(int x){//查找到相等的值的最左一位 49 int l=1,r=size,mid; 50 while(l<=r) { 51 mid=(l+r)/2; 52 if(a[mid]>=x) r=mid-1; 53 else l=mid+1; 54 } 55 return l;//!!! 56 } 57 58 inline int you_ask(int x){//查找到相等的值的最右一位 59 int l=1,r=size,mid; 60 while(l<=r) { 61 mid=(l+r)/2; 62 if(a[mid]>x) r=mid-1; 63 else l=mid+1; 64 } 65 return r;//!!! 66 } 67 68 inline void update(int x,int y){//块内暴力更改 69 int i=zuo_ask(x); 70 for(;i<size && a[i+1]<y;i++) a[i]=a[i+1]; 71 for(;i>1 && a[i-1]>y;i--) a[i]=a[i-1];//无需等号 72 a[i]=y; 73 } 74 75 inline int query(int x){ 76 return size-you_ask(x); 77 } 78 }tr[MAXN]; 79 80 inline void link(int x,int y){ next[++ecnt]=head[x]; head[x]=ecnt; to[ecnt]=y; } 81 82 inline void dfs(int x,int fa){ 83 if(tr[belong[fa]].size==S) {cnt++; belong[x]=cnt; link(belong[fa],cnt); tr[cnt].insert(w[x]);}//是belong而不是本身!!! 是cnt而不是本身 84 else { belong[x]=belong[fa]; tr[belong[fa]].insert(w[x]); } 85 father[x]=fa; 86 for(int i=first[x];i;i=next[i]) { 87 int v=to[i]; 88 if(v==fa) continue; 89 dfs(v,x); 90 } 91 } 92 93 inline void kuai_DFS(int x,int num){ 94 ans+=tr[x].query(num); 95 for(int i=head[x];i;i=next[i]) kuai_DFS(to[i],num); 96 } 97 98 inline void DFS(int x,int num){ 99 if(w[x]>num) ans++; 100 for(int i=first[x];i;i=next[i]) { 101 int v=to[i]; 102 if(v==father[x]) continue; 103 if(belong[x]==belong[v]) DFS(v,num); 104 else kuai_DFS(belong[v],num); 105 } 106 } 107 108 inline void work(){ 109 n=getint(); int x,y; 110 for(int i=1;i<n;i++) { 111 x=getint(); y=getint(); 112 next[++ecnt]=first[x]; first[x]=ecnt; to[ecnt]=y; 113 next[++ecnt]=first[y]; first[y]=ecnt; to[ecnt]=x; 114 } 115 for(int i=1;i<=n;i++) w[i]=getint(); 116 tr[0].size=S; dfs(1,0); 117 m=getint(); int ljh; 118 for(int i=1;i<=m;i++) { 119 ljh=getint(); x=getint(); y=getint(); 120 x=x^ans; y=y^ans; 121 if(ljh==0) { ans=0; DFS(x,y); printf("%d\n",ans); } 122 else if(ljh==1) { tr[belong[x]].update(w[x],y); w[x]=y; } 123 else{ 124 w[++n]=y; father[n]=x; next[++ecnt]=first[x]; first[x]=ecnt; to[ecnt]=n;//都要连接一下 125 if(tr[belong[x]].size==S) { 126 cnt++; tr[cnt].insert(y); belong[n]=cnt; 127 link(belong[x],cnt); 128 } 129 else{ 130 belong[n]=belong[x]; 131 tr[belong[x]].insert(y); 132 } 133 } 134 } 135 } 136 137 int main() 138 { 139 work(); 140 return 0; 141 }