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\n",x,ch[x][0],ch[x][1],pre[x],sz[x]);

 70         Treaval(ch[x][1]);

 71     }

 72 }

 73 void debug() {printf("%d\n",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:\n",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\n",Query(tar));

270             }

271             else printf("%d\n",Rank(num[i]));

272         }

273     }

274     return 0;

275 }

 

你可能感兴趣的:(Queue)