继续水题,终于完全掌握了伸展树了,好心痛QAQ。
1.codevs1343 蚱蜢
区间最大值查询+单点移动
最大值查询维护一个mx数组就行,单点移动么,先删除在插入
CODE:
1 /* 2 PS: 比较max值时,要写成 mx[x]=max(a[x],max(mx[l],mx[r]));形式 3 且最好把mx[0]赋值为负无穷大 4 5 取max时,注意初值问题 6 7 */ 8 9 #include<bits/stdc++.h> 10 #define N 100005 11 using namespace std; 12 int c[N][2],fa[N],a[N],size[N],mx[N],n,m,rt; 13 int read(){ 14 char c;int f=1,x=0;c=getchar(); 15 while(c>‘9‘||c<‘0‘){if(c==‘-‘)f=-1;c=getchar();} 16 while(c<=‘9‘&&c>=‘0‘)x=x*10+c-‘0‘,c=getchar(); 17 return f*x; 18 } 19 20 void pushup(int x){ 21 int l=c[x][0],r=c[x][1]; 22 size[x]=size[l]+size[r]+1; 23 mx[x]=max(a[x],max(mx[l],mx[r])); 24 } 25 26 void rotate(int x,int &k){//旋转 27 int y=fa[x],z=fa[y],l,r; 28 l=(c[y][1]==x);r=l^1; 29 if(y==k)k=x; 30 else c[z][c[z][1]==y]=x; 31 fa[c[x][r]]=y;fa[y]=x;fa[x]=z; 32 c[y][l]=c[x][r];c[x][r]=y; 33 pushup(y);pushup(x); 34 } 35 36 void splay(int x,int &k){//转化为根 37 while(x!=k){ 38 int y=fa[x],z=fa[y]; 39 if(y!=k){ 40 if(c[y][0]==x^c[z][0]==y)rotate(x,k); 41 else rotate(y,k); 42 } 43 rotate(x,k); 44 } 45 } 46 47 void build(int l,int r,int f){ 48 if(l>r)return; 49 if(l==r){c[f][l>=f]=l;fa[l]=f;mx[l]=a[l];size[l]=1;return;} 50 int mid=(l+r)>>1;build(l,mid-1,mid);build(mid+1,r,mid); 51 pushup(mid);fa[mid]=f;c[f][mid>=f]=mid; 52 } 53 54 int find(int x,int k){ 55 int l=c[x][0],r=c[x][1]; 56 if(size[l]+1==k)return x; 57 if(size[l]>=k)return find(l,k); 58 return find(r,k-size[l]-1); 59 } 60 61 void query(int l,int r){ 62 int x=find(rt,l),y=find(rt,r+2); 63 splay(x,rt);splay(y,c[x][1]); 64 printf("%d\n",mx[c[y][0]]); 65 } 66 67 void move(int l,int r){ 68 int x=find(rt,l),y=find(rt,l+2); 69 splay(x,rt);splay(y,c[x][1]); 70 int now=c[y][0];fa[now]=0; 71 c[y][0]=0;pushup(y);pushup(x); 72 x=find(rt,r+1);y=find(rt,r+2); 73 splay(x,rt);splay(y,c[x][1]); 74 c[y][0]=now;fa[now]=y; 75 pushup(y);pushup(x); 76 } 77 78 int main(){ 79 n=read();m=read(); 80 a[1]=a[n+2]=-99999999; 81 for(int i=1;i<=n;i++)a[i+1]=read(); 82 build(1,n+2,0);rt=(n+3)>>1; 83 while(m--){ 84 printf("\n"); 85 int l,r;char s[10];l=read(); 86 scanf("%s",s); 87 if(s[0]==‘D‘){r=read()+l;query(l+1,r);move(l,r-1);} 88 else{r=l-read();query(r,l-1);move(l,r-1);} 89 /* for(int i=2;i<=n+1;i++){ 90 int dada=find(rt,i); 91 printf("%d ",a[dada]); 92 }*/ 93 } 94 return 0; 95 }
2.codevs1514 书架
单点移动+单点查询
移动还是一样,先删除再插入
查询编号为S的书的上面目前有多少本书时,把S调整至根节点,输出左边儿子的元素个数即可
查询从上面数起的第S本书的编号,find(S)即可。
CODE:
1 #include<cstdio> 2 #include<cstring> 3 using namespace std; 4 5 const int INF = 1e9 + 7; 6 const int maxn = 80000 + 10; 7 8 int n, m, root; 9 int ch[maxn][2], p[maxn], a[maxn], s[maxn], v[maxn], id[maxn]; 10 11 void update(int k) { 12 s[k] = s[ch[k][0]] + s[ch[k][1]] + 1; 13 } 14 15 void rotate(int& px, int& x, int d) { 16 int t = ch[x][d]; ch[x][d] = px; ch[px][d^1] = t; 17 p[x] = p[px]; p[px] = x; p[t] = px; update(px); update(x); px = x; 18 } 19 20 void splay(int x, int& k) { 21 while(x != k) { 22 int y = p[x], z = p[y]; 23 int d = ch[y][0] == x ? 0 : 1; 24 int d2 = ch[z][0] == y ? 0 : 1; 25 if(y != k) rotate(ch[z][d2], x, d^1); else rotate(k, x, d^1); 26 } 27 } 28 29 void build(int L, int R, int P, int d) { 30 if(L == R) { s[L] = 1; p[L] = P; ch[P][d] = L; return; } 31 int M = (L+R) >> 1; 32 p[M] = P; ch[P][d] = M; 33 if(M-1 >= L) build(L, M-1, M, 0); 34 if(R >= M+1) build(M+1, R, M, 1); 35 update(M); 36 } 37 38 int find(int k, int rank) { 39 int l = ch[k][0], r = ch[k][1]; 40 if(s[l]+1 == rank) return k; 41 else if(s[l] >= rank) return find(l, rank); 42 else return find(r, rank-s[l]-1); 43 } 44 45 void remove(int k) { 46 int x, y, z; 47 x = find(root, k-1); y = find(root, k+1); 48 splay(x, root); splay(y, ch[x][1]); 49 z = ch[y][0]; ch[y][0] = 0; p[z] = s[z] = 0; 50 update(y); update(x); 51 } 52 53 void move(int k, int val) { 54 int o = id[k], x, y, rank; 55 splay(o, root); 56 rank = s[ch[o][0]] + 1; 57 remove(rank); 58 if(val == INF) x = find(root, n), y = find(root, n+1); 59 else if(val == -INF) x = find(root, 1), y = find(root, 2); 60 else x = find(root, rank+val-1), y = find(root, rank+val); 61 splay(x, root); splay(y, ch[x][1]); 62 s[o] = 1; p[o] = y; ch[y][0] = o; 63 update(y); update(x); 64 } 65 66 int main() { 67 scanf("%d%d", &n, &m); 68 for(int i = 2; i <= n+1; i++) scanf("%d", &v[i]), id[v[i]] = i; 69 build(1, n+2, 0, 1); 70 root = (n+3) >> 1; 71 72 char cmd[10]; int S, T; 73 for(int i = 1; i <= m; i++) { 74 scanf("%s%d", cmd, &S); 75 switch(cmd[0]) { 76 case ‘T‘: move(S, -INF); break; 77 case ‘B‘: move(S, INF); break; 78 case ‘I‘: scanf("%d", &T); move(S, T); break; 79 case ‘A‘: splay(id[S], root); printf("%d\n", s[ch[id[S]][0]]-1); break; 80 case ‘Q‘: printf("%d\n", v[find(root, S+1)]); break; 81 } 82 } 83 return 0; 84 }
3.codevs1743 反转卡片
简单到爆,一直区间倒置直到第一个数==1为止
CODE:
1 #include<bits/stdc++.h> 2 #define N 300005 3 using namespace std; 4 int c[N][2],fa[N],a[N],v[N],size[N],rev[N],rt,n,m; 5 int read(){ 6 char c;int f=1,x=0;c=getchar(); 7 while(c>‘9‘||c<‘0‘){if(c==‘-‘)f=-1;c=getchar();} 8 while(c<=‘9‘&&c>=‘0‘)x=x*10+c-‘0‘,c=getchar(); 9 return f*x; 10 } 11 12 void update(int x){ 13 int l=c[x][0],r=c[x][1]; 14 size[x]=size[l]+size[r]+1; 15 } 16 17 void pushdown(int x){ 18 if(rev[x]){ 19 swap(c[x][0],c[x][1]);rev[x]=0; 20 if(c[x][0])rev[c[x][0]]^=1; 21 if(c[x][1])rev[c[x][1]]^=1; 22 } 23 } 24 25 void rotate(int x,int &k){ 26 int y=fa[x],z=fa[y],l,r; 27 if(c[y][0]==x)l=0;else l=1;r=l^1; 28 if(y==k)k=x; 29 else c[z][c[z][1]==y]=x; 30 fa[x]=z;fa[y]=x;fa[c[x][r]]=y; 31 c[y][l]=c[x][r];c[x][r]=y; 32 update(y);update(x); 33 } 34 35 void splay(int x,int &k){ 36 while(x!=k){ 37 int y=fa[x],z=fa[y]; 38 if(y!=k){ 39 if(c[y][0]==x^c[z][0]==y)rotate(x,k); 40 else rotate(y,k); 41 } 42 rotate(x,k); 43 } 44 } 45 46 void build(int l,int r,int f){ 47 if(l>r)return; 48 if(l==r){ 49 size[l]=1;fa[l]=f; 50 if(l>f)c[f][1]=l; 51 else c[f][0]=l; 52 v[l]=a[l]; 53 return; 54 } 55 int mid=(l+r)>>1;v[mid]=a[mid]; 56 build(l,mid-1,mid);build(mid+1,r,mid); 57 update(mid);fa[mid]=f;c[f][mid>f]=mid; 58 } 59 60 int find(int x,int k){ 61 pushdown(x); 62 int l=c[x][0],r=c[x][1]; 63 if(size[l]+1==k)return x; 64 if(size[l]+1>k)return find(l,k); 65 return find(r,k-1-size[l]); 66 } 67 68 void rever(int l,int r){ 69 int x=find(rt,l),y=find(rt,r+2); 70 splay(x,rt);splay(y,c[x][1]); 71 rev[c[y][0]]^=1; 72 } 73 74 int main(){ 75 n=read(); 76 a[0]=a[n+2]=99999999; 77 for(int i=1;i<=n;i++)a[i+1]=read(); 78 build(1,n+2,0);rt=(3+n)>>1; 79 int x,y,ans=0; 80 while(1){ 81 y=find(rt,2); 82 x=v[y]; 83 if(x==1||ans>100000)break; 84 else rever(1,x); 85 ans++; 86 } 87 printf("%d",ans>100000?-1:ans); 88 return 0; 89 }
4.codevs1985 GameZ游戏排名系统
cnm劳资这个题调了一个晚上。。。。泪流满面,本来还可以多写2个题的。
使用hash或者map建立映射,记录某人是否已出现,如果出现的话删除再插入,否则直接插入
查询玩家排名时,直接查询他的编号,把编号调整至根节点,输出右边儿子的元素个数
最坑比的就是输出从第x位起排名前10位的人。。我先用的是查找函数,直接查找排名第x+1,x+2……点的编号并输出名字,然而效率及其低下,codevsTLE3组。后来美腻的张姐告诉我:把x~x+10区间调整至一个子树上,然后中序遍历,输出。我TM真的是个智障。。
PS:注意建立两个虚节点分别作为第一和倒数第一,来保证splay操作的正确性或者加上特殊的判断处理,但特判有些麻烦
CODE:
1 //愚蠢的TLE :输出一段连续的区间值时,不要一个一个找每个数的位置(超级费时间) 2 // 把那整个区间转移到一棵子树上,中序输出 3 #include<bits/stdc++.h> 4 #define N 250005 5 #define inf 2147483647 6 using namespace std; 7 int n,c[N][2],fa[N],val[N],size[N],tot,rt,t1,t2; 8 char s[15]; 9 struct player{ 10 int sc; 11 char na[15]; 12 }p[N]; 13 map<string,int>mp; 14 int read(){ 15 char c;int f=1,x=0;c=getchar(); 16 while(c>‘9‘||c<‘0‘){if(c==‘-‘)f=-1;c=getchar();} 17 while(c<=‘9‘&&c>=‘0‘)x=x*10+c-‘0‘,c=getchar(); 18 return f*x; 19 } 20 21 void pushup(int x){ 22 int l=c[x][0],r=c[x][1]; 23 size[x]=size[l]+size[r]+1; 24 } 25 26 void rotate(int x,int &k){ 27 int y=fa[x],z=fa[y],l,r; 28 if(c[y][0]==x)l=0;else l=1;r=l^1; 29 if(y==k)k=x; 30 else c[z][c[z][1]==y]=x; 31 fa[x]=z;fa[y]=x;fa[c[x][r]]=y; 32 c[y][l]=c[x][r];c[x][r]=y; 33 pushup(y);pushup(x); 34 } 35 36 void splay(int x,int &k){ 37 while(x!=k){ 38 int y=fa[x],z=fa[y]; 39 if(y!=k){ 40 if((c[y][0]==x)^(c[z][0]==y))rotate(x,k); 41 else rotate(y,k); 42 } 43 rotate(x,k); 44 } 45 } 46 47 void insert(int v,int num){ 48 if(!rt){rt=num;val[num]=v;size[rt]=1;return;} 49 int p=rt,z; 50 while(p){ 51 size[p]++;z=p; 52 if(val[p]<v)p=c[p][1]; 53 else p=c[p][0]; 54 } 55 val[num]=v;c[z][v>val[z]]=num; 56 fa[num]=z;size[num]=1; 57 splay(num,rt); 58 } 59 60 int find(int x,int k){ 61 int l=c[x][0],r=c[x][1]; 62 if(size[r]+1==k)return x; 63 if(size[r]>=k)return find(r,k); 64 return find(l,k-size[r]-1); 65 } 66 67 int trans(){ 68 int i=0,x=0; 69 while(s[i]){x=x*10+s[i]-‘0‘;i++;} 70 return x; 71 } 72 73 void del(int x){ 74 splay(x,rt); 75 int l=c[x][0],r=c[x][1]; 76 while(c[l][1])l=c[l][1]; 77 while(c[r][0])r=c[r][0]; 78 splay(l,rt);splay(r,c[l][1]); 79 fa[c[r][0]]=0;c[r][0]=0; 80 pushup(r);pushup(l); 81 } 82 83 void print(int x){ 84 if(!x)return; 85 print(c[x][1]); 86 printf("%s ",p[x].na); 87 print(c[x][0]); 88 } 89 90 void find_name(int a){ 91 int b=min(a+11,tot); 92 int x=find(rt,b),y=find(rt,a); 93 splay(x,rt);splay(y,c[x][1]); 94 pushup(y);pushup(x); 95 print(c[y][0]); 96 printf("\n"); 97 } 98 99 int main(){ 100 n=read(); 101 insert(inf,1); 102 insert(-1,2); 103 tot=2; 104 for(int i=1;i<=n;i++){ 105 char ch;scanf(" %c",&ch); 106 if(ch==‘+‘){ 107 scanf("%s",p[++tot].na);p[tot].sc=read(); 108 if(mp[p[tot].na]){ 109 int ps=mp[p[tot].na]; 110 del(ps); 111 p[ps].sc=p[tot].sc; 112 insert(p[tot].sc,ps); 113 tot--; 114 } 115 else { 116 mp[p[tot].na]=tot; 117 insert(p[tot].sc,tot); 118 } 119 } 120 else { 121 scanf("%s",s); 122 if(s[0]>=‘1‘&&s[0]<=‘9‘){ 123 int pos=trans(); 124 find_name(pos); 125 } 126 else{ 127 int ps=mp[s]; 128 splay(ps,rt); 129 printf("%d\n",size[c[rt][1]]); 130 } 131 } 132 133 } 134 return 0; 135 }
记录一件事情,今晚lgh和ypj吵架了,原因是我们想离开高二机房,他不准,lgh又不肯退步,于是造成了惨剧(开玩笑)。。后来ypj就一直教育他(期间再次提到了某位打游戏翻车的同学),搞得他心情很不好啊,于是他就开始挤兑ypj,我估计后来ypj也非常不高兴。
其实这件事呢,我们是不占理的。首先是没给ypj说一声就想走,十分的不尊重,其二就是lgh可能被愤怒冲昏了头脑,说话非常的冲,让人听了很不爽,交流方式确实有些问题。当然ypj说话也有些问题,他非常的不善言辞(就是瞎几把说话)。在我看来,和ypj吵并不值得,因为他本来就很不可理喻,思想跟我们完全脱节。以后遇到这种情况,我们最好就是不跟他说屁话,打代码。他bb够了自己就离开了,免得吵起来双方都不爽。
今天ypj讲了主席树,我听懂了思想,但具体代码实现还有些懵逼,明天再看看。。
chair-man tree