题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1890
题目中涉及数的反转和删除操作,需要用Splay tree来实现。首先对数列排序,得到每个数在数列中的下标x。Splay tree的每个节点标记以它为根的子树是否需要反转,用到懒惰操作,保证nlogn,在每次操作的时候Push_Down()和Push_Up。在建树的时候是数的下标为节点标号建立数,如果要询问数num[i],则把num[i]在数列中的下标旋转到根节点root,size[ch[root][0]]+已经排好序的数的数目就是答案。注意,这里因为涉及到数的反转操作,因此在Splay()操作的时候,应该先Push_Down(),然后再判断旋转操作。。
1 //STATUS:C++_AC_256MS_2700KB 2 #include <functional> 3 #include <algorithm> 4 #include <iostream> 5 //#include <ext/rope> 6 #include <fstream> 7 #include <sstream> 8 #include <iomanip> 9 #include <numeric> 10 #include <cstring> 11 #include <cassert> 12 #include <cstdio> 13 #include <string> 14 #include <vector> 15 #include <bitset> 16 #include <queue> 17 #include <stack> 18 #include <cmath> 19 #include <ctime> 20 #include <list> 21 #include <set> 22 #include <map> 23 using namespace std; 24 //using namespace __gnu_cxx; 25 //define 26 #define pii pair<int,int> 27 #define mem(a,b) memset(a,b,sizeof(a)) 28 #define lson l,mid,rt<<1 29 #define rson mid+1,r,rt<<1|1 30 #define PI acos(-1.0) 31 //typedef 32 typedef __int64 LL; 33 typedef unsigned __int64 ULL; 34 //const 35 const int N=100010; 36 const int INF=0x3f3f3f3f; 37 const int MOD=100000,STA=8000010; 38 const LL LNF=1LL<<60; 39 const double EPS=1e-8; 40 const double OO=1e15; 41 const int dx[4]={-1,0,1,0}; 42 const int dy[4]={0,1,0,-1}; 43 const int day[13]={0,31,28,31,30,31,30,31,31,30,31,30,31}; 44 //Daily Use ... 45 inline int sign(double x){return (x>EPS)-(x<-EPS);} 46 template<class T> T gcd(T a,T b){return b?gcd(b,a%b):a;} 47 template<class T> T lcm(T a,T b){return a/gcd(a,b)*b;} 48 template<class T> inline T lcm(T a,T b,T d){return a/d*b;} 49 template<class T> inline T Min(T a,T b){return a<b?a:b;} 50 template<class T> inline T Max(T a,T b){return a>b?a:b;} 51 template<class T> inline T Min(T a,T b,T c){return min(min(a, b),c);} 52 template<class T> inline T Max(T a,T b,T c){return max(max(a, b),c);} 53 template<class T> inline T Min(T a,T b,T c,T d){return min(min(a, b),min(c,d));} 54 template<class T> inline T Max(T a,T b,T c,T d){return max(max(a, b),max(c,d));} 55 //End 56 57 #define Key_value ch[ch[root][1]][0] 58 int pre[N],ch[N][2]; //分别表示父结点,键值,左右孩子(0为左孩子,1为右孩子),根结点,结点数量 59 int sz[N],st[N]; //子树规模,内存池 60 int root,tot,top; //根节点,根节点数量,内存池容量 61 //题目特定数据 62 struct Node{ 63 int num,idx; 64 }nod[N]; 65 bool rev[N]; 66 int n; 67 //debug部分copy from hh 68 void Treaval(int x) { 69 if(x) { 70 Treaval(ch[x][0]); 71 printf("结点%2d:左儿子 %2d 右儿子 %2d 父结点 %2d size = %2d rev = %2d ",x,ch[x][0],ch[x][1],pre[x],sz[x],rev[x]); 72 Treaval(ch[x][1]); 73 } 74 } 75 void debug() {printf("%d ",root);Treaval(root);} 76 //以上Debug 77 //新建一个结点 78 void NewNode(int &x,int fa,int k) 79 { 80 // if(top)x=st[--top]; 81 // else x=++tot; 82 x=k; 83 pre[x]=fa; 84 sz[x]=1; 85 rev[x]=0; 86 ch[x][0]=ch[x][1]=0; //左右孩子为空 87 } 88 89 void Push_Up(int x) 90 { 91 sz[x]=sz[ch[x][0]]+sz[ch[x][1]]+1; 92 } 93 94 void Push_Down(int x) 95 { 96 if(rev[x]){ 97 rev[ch[x][0]]^=1; 98 rev[ch[x][1]]^=1; 99 swap(ch[x][0],ch[x][1]); 100 rev[x]=0; 101 } 102 } 103 //旋转,kind为1为右旋,kind为0为左旋 104 void Rotate(int x,int kind) 105 { 106 int y=pre[x],z=pre[y]; 107 Push_Down(y); 108 Push_Down(x); //先把y的标记向下传递,再把x的标记往下传递 109 //类似SBT,要把其中一个分支先给父节点 110 ch[y][!kind]=ch[x][kind]; 111 pre[ch[x][kind]]=y; 112 //如果父节点不是根结点,则要和父节点的父节点连接起来 113 if(z)ch[z][ch[z][1]==y]=x; 114 pre[x]=z; 115 ch[x][kind]=y; 116 pre[y]=x; 117 Push_Up(y); //维护y结点,不要维护x节点,x节点会再次Push_Down,最后维护一下x节点即可 118 } 119 //Splay调整,将根为r的子树调整为goal 120 void Splay(int x,int goal) 121 { 122 int y,z,kind; 123 while(pre[x]!=goal){ 124 //父节点即是目标位置,goal为0表示,父节点就是根结点 125 y=pre[x]; 126 Push_Down(pre[y]);Push_Down(y);Push_Down(x); //设计到反转操作,要先更新,然后在判断!! 127 if(pre[y]==goal){ 128 Rotate(x,ch[y][0]==x); 129 } 130 else { 131 kind=ch[pre[y]][0]==y; 132 //两个方向不同,则先左旋再右旋 133 if(ch[y][kind]==x){ 134 Rotate(x,!kind); 135 Rotate(x,kind); 136 } 137 //两个方向相同,相同方向连续两次 138 else { 139 Rotate(y,kind); 140 Rotate(x,kind); 141 } 142 } 143 } 144 //更新根结点 145 Push_Up(x); 146 if(goal==0)root=x; 147 } 148 //建树,中间结点先建立,然后分别对区间两端在左右子树建立 149 void BuildTree(int &x,int l,int r,int fa) 150 { 151 if(l>r)return; 152 int mid=(l+r)>>1; 153 NewNode(x,fa,mid); 154 BuildTree(ch[x][0],l,mid-1,x); 155 BuildTree(ch[x][1],mid+1,r,x); 156 Push_Up(x); 157 } 158 159 int cmp(Node a,Node b) 160 { 161 return a.num!=b.num?a.num<b.num:a.idx<b.idx; 162 } 163 164 void Init() 165 { 166 root=tot=top=0; 167 ch[root][0]=ch[root][1]=pre[0]=sz[0]=rev[0]=0; 168 169 for(int i=1;i<=n;i++){ 170 scanf("%d",&nod[i].num); 171 nod[i].idx=i; 172 } 173 sort(nod+1,nod+n+1,cmp); 174 BuildTree(root,1,n,0); 175 } 176 177 int Get_Max(int x) 178 { 179 Push_Down(x); 180 while(ch[x][1]){ 181 x=ch[x][1]; 182 Push_Down(x); 183 } 184 return x; 185 } 186 187 void Remove() 188 { 189 if(ch[root][0]==0){ 190 root=ch[root][1]; 191 pre[root]=0; 192 } 193 else { 194 int x=Get_Max(ch[root][0]); 195 Splay(x,root); 196 ch[x][1]=ch[root][1]; 197 pre[ch[root][1]]=x; 198 root=x; 199 pre[root]=0; 200 Push_Up(root); 201 } 202 } 203 204 int main() 205 { 206 // freopen("in.txt","r",stdin); 207 int i,j; 208 while(~scanf("%d",&n) && n) 209 { 210 Init(); 211 for(i=1;i<n;i++){ 212 Splay(nod[i].idx,0); 213 rev[ch[root][0]]^=1; 214 printf("%d ",i+sz[ch[root][0]]); 215 Remove(); 216 } 217 printf("%d ",n); 218 } 219 return 0; 220 }