HDU-3436 Queue-jumpers 树状数组 | Splay tree删除,移动

  题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3436

  树状数组做法<猛戳>

  Splay tree的经典题目,有删除和移动操作。首先要离散化各个点,而且对于没有区间还要缩点。对于Top操作,先把目标节点删除,然后移到最左端。Query操作,Splay(tar,0),然后直接访问size。对于Rank操作,通过size产找即可。注意,在每次更新后,都要把处理过的节点都要Splay(tar,0)才能保证复杂度为O(log n),因为这样才能方便下次的访问,因为这个TLE了一个下午+一个晚上。。。。Splay()操作太神了。。

  1 //STATUS:C++_AC_187MS_4196KB
  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<<1],ch[N<<1][2];  //分别表示父结点,键值,左右孩子(0为左孩子,1为右孩子),根结点,结点数量
 59 int sz[N<<1],st[N];   //子树规模,内存池
 60 int root,tot,top;   //根节点,根节点数量,内存池容量
 61 //题目特定数据
 62 int op[N],cnt[N<<1],s[N<<1],e[N<<1];
 63 int num[N],p[N];
 64 int T,n,m,up;
 65 //debug部分copy from hh
 66 void Treaval(int x) {
 67     if(x) {
 68         Treaval(ch[x][0]);
 69         printf("结点%2d:左儿子 %2d 右儿子 %2d 父结点 %2d size = %2d
",x,ch[x][0],ch[x][1],pre[x],sz[x]);
 70         Treaval(ch[x][1]);
 71     }
 72 }
 73 void debug() {printf("%d
",root);Treaval(root);}
 74 //以上Debug
 75 //新建一个结点
 76 void NewNode(int &x,int fa,int k,int size)
 77 {
 78  //   if(top)x=st[--top];
 79  //   else x=++tot;
 80     x=k;
 81     pre[x]=fa;
 82     sz[x]=cnt[x]=size;
 83     ch[x][0]=ch[x][1]=0;  //左右孩子为空
 84 }
 85 
 86 inline void Push_Up(int x)
 87 {
 88     sz[x]=sz[ch[x][0]]+sz[ch[x][1]]+cnt[x];
 89 }
 90 //旋转,kind为1为右旋,kind为0为左旋
 91 void Rotate(int x,int kind)
 92 {
 93     int y=pre[x],z=pre[y];
 94     //类似SBT,要把其中一个分支先给父节点
 95     ch[y][!kind]=ch[x][kind];
 96     pre[ch[x][kind]]=y;
 97     //如果父节点不是根结点,则要和父节点的父节点连接起来
 98     if(z)ch[z][ch[z][1]==y]=x;
 99     pre[x]=z;
100     ch[x][kind]=y;
101     pre[y]=x;
102     Push_Up(y);  //维护y结点,不要维护x节点,x节点会再次Push_Down,最后维护一下x节点即可
103 }
104 //Splay调整,将根为r的子树调整为goal
105 void Splay(int x,int goal)
106 {
107     int y,z,kind;
108     while(pre[x]!=goal){
109         //父节点即是目标位置,goal为0表示,父节点就是根结点
110         y=pre[x];
111         if(pre[y]==goal){
112             Rotate(x,ch[y][0]==x);
113         }
114         else {
115             kind=ch[pre[y]][0]==y;
116             //两个方向不同,则先左旋再右旋
117             if(ch[y][kind]==x){
118                 Rotate(x,!kind);
119                 Rotate(x,kind);
120             }
121             //两个方向相同,相同方向连续两次
122             else {
123                 Rotate(y,kind);
124                 Rotate(x,kind);
125             }
126         }
127     }
128     //更新根结点
129     Push_Up(x);
130     if(goal==0)root=x;
131 }
132 
133 int Get_Min(int x)
134 {
135     while(ch[x][0])x=ch[x][0];
136     return x;
137 }
138 //建树,中间结点先建立,然后分别对区间两端在左右子树建立
139 void BuildTree(int &x,int l,int r,int fa)
140 {
141     if(l>r)return;
142     int mid=(l+r)>>1;
143     NewNode(x,fa,mid,e[mid]-s[mid]+1);
144     BuildTree(ch[x][0],l,mid-1,x);
145     BuildTree(ch[x][1],mid+1,r,x);
146     Push_Up(x);
147 }
148 
149 void Init()
150 {
151     root=tot=top=0;
152     ch[0][0]=ch[0][1]=pre[0]=sz[0]=cnt[0]=0;
153 
154     int i,t,k;
155     char ss[8];
156     p[0]=0,t=1;
157     for(i=1;i<=m;i++){
158         scanf("%s%d",ss,&num[i]);
159         op[i]=ss[0]=='T'?1:ss[0]=='Q'?2:0;
160         if(op[i])p[t++]=num[i];
161     }
162     sort(p,p+t);
163     for(k=1,i=2;i<t;i++)
164         if(p[i]!=p[k])p[++k]=p[i];
165     for(i=1,up=0;i<=k;i++){
166         if(p[i]-p[i-1]>1){
167             s[++up]=p[i-1]+1;
168             e[up]=p[i]-1;
169         }
170         s[++up]=p[i];
171         e[up]=p[i];
172     }
173     if(e[up]!=n){
174         ++up;
175         s[up]=e[up-1]+1;
176         e[up]=n;
177     }
178     BuildTree(root,1,up,0);
179 }
180 //删除编号为x的节点
181 void Delete(int x)
182 {
183     int y=pre[x],s;
184     if(sz[x]==cnt[x]){
185         ch[y][ch[y][1]==x]=0;
186         s=y;
187     }
188     else if(ch[x][0]==0 || ch[x][1]==0){
189         s=ch[x][0]?ch[x][0]:ch[x][1];
190         if(y)ch[y][ch[y][1]==x]=s;
191         pre[s]=y;
192     }
193     else {
194         s=Get_Min(ch[x][1]);
195         Splay(s,x);
196         if(ch[x][0]){
197             ch[s][0]=ch[x][0];
198             pre[ch[x][0]]=s;
199         }
200         pre[s]=y;
201         if(y)ch[y][ch[y][1]==x]=s;
202     }
203     if(y==0)root=s;
204     Splay(s,0);
205 }
206 
207 void Top(int tar)
208 {
209     if(sz[root]==cnt[root])return;
210     Delete(tar);
211     int x=Get_Min(root);
212     ch[x][0]=tar;
213     pre[tar]=x;
214     sz[tar]=cnt[tar];
215     ch[tar][0]=ch[tar][1]=0;
216     Splay(tar,0);
217 }
218 
219 int Query(int tar)
220 {
221     Splay(tar,0);
222     return sz[ch[root][0]]+cnt[tar];
223 }
224 
225 int Rank(int k)
226 {
227     int x=root;
228     while(1){
229         if(k>sz[ch[x][0]] && k<=sz[ch[x][0]]+cnt[x]){
230             k-=sz[ch[x][0]];
231             break;
232         }
233         else if(k<=sz[ch[x][0]])
234             x=ch[x][0];
235         else {
236             k-=sz[ch[x][0]]+cnt[x];
237             x=ch[x][1];
238         }
239     }
240     return s[x]+k-1;
241 }
242 
243 int binary(int l,int r,int tar)
244 {
245     int mid;
246     while(l<r){
247         mid=(l+r)>>1;
248         if(e[mid]<tar)l=mid+1;
249         else if(s[mid]>tar)r=mid;
250         else return mid;
251     }
252     return -1;
253 }
254 
255 int main()
256 {
257  //   freopen("in.txt","r",stdin);
258     int i,j,ca=1,tar;
259     scanf("%d",&T);
260     while(T--)
261     {
262         scanf("%d%d",&n,&m);
263         Init();
264         printf("Case %d:
",ca++);
265         for(i=1;i<=m;i++){
266             if(op[i]){
267                 tar=binary(1,up+1,num[i]);
268                 if(op[i]==1)Top(tar);
269                 else printf("%d
",Query(tar));
270             }
271             else printf("%d
",Rank(num[i]));
272         }
273     }
274     return 0;
275 }
原文地址:https://www.cnblogs.com/zhsl/p/3213440.html