NOI2004 郁闷的出纳员 splay
http://www.lydsy.com/JudgeOnline/problem.php?id=1503
抄别人模板过的...打了点注释算是大概懂了...
/********************* Template ************************/ #include <set> #include <map> #include <list> #include <cmath> #include <ctime> #include <deque> #include <queue> #include <stack> #include <bitset> #include <cstdio> #include <string> #include <vector> #include <cassert> #include <cstdlib> #include <cstring> #include <sstream> #include <fstream> #include <numeric> #include <iomanip> #include <iostream> #include <algorithm> #include <functional> using namespace std; #define BUG cout<<" BUG! "<<endl; #define LINE cout<<" ------------------ "<<endl; #define FIN freopen("in.txt","r",stdin); #pragma comment (linker,"/STACK:102400000,102400000") template<class T> inline T L(T a) {return (a << 1);} template<class T> inline T R(T a) {return (a << 1 | 1);} template<class T> inline T lowbit(T a) {return (a & -a);} template<class T> inline T Mid(T a,T b) {return ((a + b) / 2);} template<class T> inline T gcd(T a,T b) {return b ? gcd(b,a%b) : a;} template<class T> inline T lcm(T a,T b) {return a / gcd(a,b) * b;} template<class T> inline T Min(T a,T b) {return a < b ? a : b;} template<class T> inline T Max(T a,T b) {return a > b ? a : b;} template<class T> inline T Min(T a,T b,T c) {return min(min(a,b),c);} template<class T> inline T Max(T a,T b,T c) {return max(max(a,b),c);} template<class T> inline T Min(T a,T b,T c,T d) {return min(min(a,b),min(c,d));} template<class T> inline T Max(T a,T b,T c,T d) {return max(max(a,b),max(c,d));} template<class T> inline void mem(T &a,int b) {memset(a,b,sizeof(a));} template<class T> inline T exGCD(T a, T b, T &x, T &y){ // if(!b) return x = 1,y = 0,a; T res = exGCD(b,a%b,x,y),tmp = x; x = y,y = tmp - (a / b) * y; return res; } typedef long long LL; typedef unsigned long long ULL; //typedef __int64 LL; typedef unsigned __int64 ULL; const LL LINF = 1LL << 60; const int MOD = 1000000007; const int INF = 0x7fffffff; const int MAXN = (int)1e5+5; const double EPS = 1e-8; const double DINF = 1e15; const double PI = acos(-1.0); /********************* By F *********************/ int n,lim,num,ans; char op; struct splay{ int ch[MAXN][2]; // 0:左节点 1:右节点 int pre[MAXN]; // 父节点 int cnt[MAXN]; int sz[MAXN]; // size[] 保存节点 int val[MAXN]; int root,top; int sum; inline void up(int x){ sz[x] = cnt[x] + sz[ch[x][0]] + sz[ch[x][1]]; } inline void Rotate(int x,int c){ // 0 左旋, 1 右旋 int y = pre[x],z = pre[y]; // y为x的父亲,z为y的父亲 ch[y][!c] = ch[x][c]; // 举例-> 如果右旋:x的右节点 -> y的左节点 pre[ch[x][c]] = y; // 标记: x右节点的父亲 -> y pre[x] = z; // y旋转到x下面 -> 标记: x的父节点 -> y的父节点 if(z != 0) // 若y不是根节点,y的父节点转为x的父节点 ch[z][ch[z][1] == y] = x; ch[x][c] = y; // x的右节点已经给了y的左节点,所以x的右节点变为y pre[y] = x; // y的父节点变为x up(y); // ? } inline void Splay(int x,int goal){ while(pre[x] != goal){ if(pre[pre[x]] == goal) Rotate(x,ch[pre[x]][0] == x); // 如果x的祖父是目标节点,只需要转一次 else{ int y = pre[x],z = pre[y],c = (ch[z][0] == y); if(ch[y][c] == x) Rotate(x,!c),Rotate(x,c); // z字旋转 x左右各转一次 else Rotate(y,c),Rotate(x,c); // 1字旋转 先转y 后转x } } up(x); // ? if(goal == 0) root = x; // 0节点是根节点的父节点,如果要转到0下 则该点为根 } inline void Init(){ // 初始化 ch[0][0] = ch[0][1] = pre[0] = sz[0] = cnt[0] = sum = root = top = 0; } // inline void RTO(int k,int goal){ // 将第k位数旋转到goal的下面 // int x = root; // while(sz[ch[x][0]] != k-1){ // if(k < sz[ch[x][0]]+1) x = ch[x][0]; // else{ // k -= (sz[ch[x][0]]+1); // x = ch[x][1]; // } // } // Splay(x,goal); // } inline void Insert(int &x,int key,int f){ if(!x){ // 如果x是叶子节点 x = ++top; // 节点标号,从1开始 ch[x][0] = ch[x][1] = 0; // 子节点设置0 sz[x] = cnt[x] = 1; val[x] = key; pre[x] = f; Splay(x,0); // 将该点转到根 return ; } if(key == val[x]){ // 如果权值重复 cnt[x]++; // cnt[x]++ sz[x]++; // size[x]++ Splay(x,0); // 将该点转到根 return ; } else if(key < val[x]) Insert(ch[x][0],key,x); // 保证平衡树的性质 else if(key > val[x]) Insert(ch[x][1],key,x); up(x); } inline void del(int &x,int f){ if(!x) return ; // 如果x是叶子节点 if(val[x] >= lim){ // 从x左边开始删 del(ch[x][0],x); }else{ sum += sz[ch[x][0]] + cnt[x]; x = ch[x][1]; pre[x] = f; if(f == 0) root = x; del(x,f); } if(x) up(x); } inline int find_kth(int x,int k){ if(k < sz[ch[x][0]]+1) return find_kth(ch[x][0],k); else if(k > sz[ch[x][0] ] + cnt[x]) return find_kth(ch[x][1],k-sz[ch[x][0]]-cnt[x]); else{ Splay(x,0); return val[x]; } } inline void show(int x){ if(x){ printf("%d: Left: %d Right: %d Val: %d Size: %d\n",x,ch[x][0],ch[x][1],val[x],sz[x]); show(ch[x][0]); show(ch[x][1]); } } }s; int main(){ while(~scanf("%d%d",&n,&lim)){ s.Init(); int limit = lim; for(int i = 0 ; i < n ; i++){ getchar(); scanf("%c %d",&op,&num); if(op == 'I'){ if(num < limit) continue; s.Insert(s.root,num+lim-limit,0); // 从根节点开始插入 } if(op == 'A') lim -= num; if(op == 'S'){ lim += num; if(s.sz[s.root] > 0) s.del(s.root,0); } if(op == 'F'){ int sz = s.sz[s.root]; if(num > sz) printf("-1\n"); else printf("%d\n",s.find_kth(s.root,sz-num+1)-lim+limit); } //s.show(s.root); } printf("%d\n",s.sum); } return 0; }