bzoj1861[Zjoi2006]Book 书架

bzoj1861[Zjoi2006]Book 书架

题意:

维护一个序列,支持移动元素,查询元素是第几个,查询第k个元素编号。

题解:

可以用treap和splay,我写的是splay。移动元素就是先删一个节点在将这个节点插入到对应位置,注意各种分操作(如splay、find)的次序性。反思:本弱又WA又T,最后自己造了一个极限数据发现死循环了,对着大数据调了半天才发现是分操作次序不当导致错误。

代码:

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #define inc(i,j,k) for(int i=j;i<=k;i++)
 5 #define maxn 80100
 6 using namespace std;
 7 
 8 int ch[maxn][2],fa[maxn],v[maxn],sz[maxn],pos[maxn],root,book[maxn],tot,n,m;
 9 inline int read(){
10     char ch=getchar(); int f=1,x=0;
11     while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();};
12     while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
13     return f*x;
14 }
15 inline void update(int x){sz[x]=sz[ch[x][0]]+sz[ch[x][1]]+1;}
16 void rotate(int x){
17     if(!x||!fa[x])return; int a=fa[x],b=fa[fa[x]]; bool c=x==ch[fa[x]][1],d=a==ch[fa[a]][1];
18     if(b)ch[b][d]=x; fa[x]=b; ch[a][c]=ch[x][!c]; if(ch[x][!c])fa[ch[x][!c]]=a; ch[x][!c]=a; fa[a]=x;
19     update(a); update(x); if(b)update(b);
20 }
21 void splay(int x,int y){
22     if(x==y)return; int z=fa[y];
23     while(fa[x]!=z){
24         if(fa[x]!=y)(x==ch[fa[x]][1])^(fa[x]==ch[fa[fa[x]]][1])?rotate(x):rotate(fa[x]);
25         rotate(x);
26     }
27     if(root==y)root=x;
28 }
29 void build(int x,int l,int r){
30     int mid=l+r>>1; v[x]=book[mid]; pos[book[mid]]=x;
31     if(l<=mid-1)ch[x][0]=++tot,build(ch[x][0],l,mid-1),fa[ch[x][0]]=x;
32     if(mid+1<=r)ch[x][1]=++tot,build(ch[x][1],mid+1,r),fa[ch[x][1]]=x;
33     update(x);
34 }
35 int querynum(int x,int k){
36     if(k<=sz[ch[x][0]])return querynum(ch[x][0],k);
37     if(k==sz[ch[x][0]]+1)return x;
38     return querynum(ch[x][1],k-sz[ch[x][0]]-1);
39 }
40 int queryrank(int x){
41     splay(x,root); return sz[ch[x][0]];
42 }
43 int pre(int y){
44     splay(y,root); return querynum(ch[y][0],sz[ch[y][0]]);
45 }
46 int nex(int y){
47     splay(y,root); return querynum(ch[y][1],1);
48 }
49 void add(int x,int y,int z){
50     splay(y,root); splay(x,ch[root][0]); ch[x][1]=z; fa[z]=x; update(x); update(root);
51 }
52 void erase(int z){
53     int x=pre(z),y=nex(z); splay(y,root); splay(x,ch[root][0]); ch[x][1]=0; fa[z]=0; update(x); update(root);
54 }
55 void top(int s){
56     int x=pos[s]; erase(x); int y=querynum(root,1),z=nex(y); add(y,z,x);
57 }
58 void bottom(int s){
59     int x=pos[s]; erase(x); int y=querynum(root,sz[root]-1),z=nex(y); add(y,z,x);
60 }
61 void insert(int s,int t){
62     int a1=pos[s],a2=queryrank(a1)+t; erase(a1); int a3=querynum(root,a2),a4=nex(a3); add(a3,a4,a1);
63 }
64 int ask(int s){return queryrank(pos[s])-1;}
65 int query(int s){return v[querynum(root,s+1)];}
66 int main(){
67     n=read(); m=read(); inc(i,2,n+1)book[i]=read(); tot=root=1; build(root,1,n+2);
68     inc(i,1,m){
69         char opt[8]; scanf("%s",opt);
70         if(opt[0]=='T'){int a=read(); top(a);}
71         if(opt[0]=='B'){int a=read(); bottom(a);}
72         if(opt[0]=='I'){int a=read(),b=read(); insert(a,b);}
73         if(opt[0]=='A'){int a=read(); printf("%d\n",ask(a));}
74         if(opt[0]=='Q'){int a=read(); printf("%d\n",query(a));}
75     }
76     return 0;
77 }

 

20160811

转载于:https://www.cnblogs.com/YuanZiming/p/5769472.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
题目描述 有一个 $n$ 个点的棋盘,每个点上有一个数字 $a_i$,你需要从 $(1,1)$ 走到 $(n,n)$,每次只能往右或往下走,每个格子只能经过一次,路径上的数字和为 $S$。定义一个点 $(x,y)$ 的权值为 $a_x+a_y$,求所有满足条件的路径中,所有点的权值和的最小值。 输入格式 第一行一个整数 $n$。 接下来 $n$ 行,每行 $n$ 个整数,表示棋盘上每个点的数字。 输出格式 输出一个整数,表示所有满足条件的路径中,所有点的权值和的最小值。 数据范围 $1\leq n\leq 300$ 输入样例 3 1 2 3 4 5 6 7 8 9 输出样例 25 算法1 (树形dp) $O(n^3)$ 我们可以先将所有点的权值求出来,然后将其看作是一个有权值的图,问题就转化为了在这个图中求从 $(1,1)$ 到 $(n,n)$ 的所有路径中,所有点的权值和的最小值。 我们可以使用树形dp来解决这个问题,具体来说,我们可以将这个图看作是一棵树,每个点的父节点是它的前驱或者后继,然后我们从根节点开始,依次向下遍历,对于每个节点,我们可以考虑它的两个儿子,如果它的两个儿子都被遍历过了,那么我们就可以计算出从它的左儿子到它的右儿子的路径中,所有点的权值和的最小值,然后再将这个值加上当前节点的权值,就可以得到从根节点到当前节点的路径中,所有点的权值和的最小值。 时间复杂度 树形dp的时间复杂度是 $O(n^3)$。 C++ 代码 算法2 (动态规划) $O(n^3)$ 我们可以使用动态规划来解决这个问题,具体来说,我们可以定义 $f(i,j,s)$ 表示从 $(1,1)$ 到 $(i,j)$ 的所有路径中,所有点的权值和为 $s$ 的最小值,那么我们就可以得到如下的状态转移方程: $$ f(i,j,s)=\min\{f(i-1,j,s-a_{i,j}),f(i,j-1,s-a_{i,j})\} $$ 其中 $a_{i,j}$ 表示点 $(i,j)$ 的权值。 时间复杂度 动态规划的时间复杂度是 $O(n^3)$。 C++ 代码

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值