这道题整整搞了我5天。。。。用到了数列的插入,删除和查询第K大
写的第一道平衡树题。。可以用各种平衡树和线段树来写,不失为一道极佳的平衡树练手题(据说树状数组也可以??Orz)
一开始是用splay,splay网上的code大部分都用了指针我根本看不懂。
后来找葱娘的ACcode用数组写的才总算看懂一点。。我理解了一晚上,写了一上午,调了一下午加晚上。。
葱娘的代码就是神,一开始我还以为要用到区间修改,后面发现葱娘用一个变量记录增量就可以了(Orz!!)
附上单旋SPLAYcode,这道题数据比较水,双旋单旋差不多
/*
ID:WULALA
PROB:splay bzoj1503
LANG:C++
*/
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <iostream>
#include <ctime>
#include <set>
#define N 100008
#define M
#define mod
#define mid(l,r) ((l+r) >> 1)
#define INF 0x7ffffff
using namespace std;
struct node
{
int l,r,f,key,s,v;
}tree[N];
int n,m,root,delta,l,tot = 1;
inline void update(int x)
{
tree[x].s = tree[tree[x].l].s + tree[tree[x].r].s + 1;
}
inline void zig(int &x)
{
int y = tree[x].f;
int z = tree[y].f;
if (y == tree[z].l) tree[z].l = x;
else tree[z].r = x;
tree[x].f = z;
tree[y].l = tree[x].r;
tree[tree[x].r].f = y;
tree[x].r = y;
tree[y].f = x;
update(y); update(x);
if (y == root) root = x;
}
inline void zag(int &x)
{
int y = tree[x].f;
int z = tree[y].f;
if (y == tree[z].l) tree[z].l = x;
else tree[z].r = x;
tree[x].f = z;
tree[y].r = tree[x].l;
tree[tree[x].l].f = y;
tree[y].f = x;
tree[x].l = y;
update(y); update(x);
if (y == root) root = x;
}
void splay(int &x,int d)
{
while (tree[x].f != d)
{
if (tree[tree[x].f].l == x) zig(x);
else zag(x);
}
}
void insert(int k)
{
if (!root)
{
root = ++tot;
tree[tot].key = k;
tree[tot].s = 1;
return;
}
int p = root,z;
while(p)
{
z = p;
++tree[p].s;
if (k < tree[p].key) p = tree[p].l;
else p = tree[p].r;
}
if (tree[z].key>k) tree[z].l = ++tot;
else tree[z].r = ++tot;
tree[tot].key = k;
tree[tot].s = 1;
tree[tot].f = z;
splay(tot,0);
}
int find(int x,int k)
{
if (k <= tree[tree[x].r].s)
return (find(tree[x].r,k));
if (k == tree[tree[x].r].s+1)
return tree[x].key;
return find(tree[x].l,k-tree[tree[x].r].s-1);
}
int dec(int &x,int f)
{
if (!x) return 0;
int k;
if (tree[x].key + delta < m)
{
k = dec(tree[x].r,x) + tree[tree[x].l].s + 1;
tree[tree[x].r].s = tree[x].s-k;
x = tree[x].r;
tree[x].f = f;
}
else
{
k = dec(tree[x].l,x);
tree[x].s -= k;
}
return k;
}
int main()
{
// freopen("input.txt","r",stdin);
// freopen("output.txt","w",stdout);
scanf("%d%d",&n,&m);
while(n--)
{
char c[1];
int k;
scanf("%s%d",&c,&k);
if (c[0] == 'I' && k >= m) insert(k - delta);
else if (c[0] == 'F')
printf("%d\n",k <= tree[root].s?find(root,k)+delta:-1);
else if (c[0] == 'A')
delta += k;
else if (c[0] == 'S')
{delta -= k; l+=dec(root,0);}
}
printf("%d\n",l);
return 0;
}
看了一下HZW的treap在较好情况下比我的快了3倍。。人家还会用线段树做。。好自卑。。我连随机函数都不会用(orz!!)
然后又用sbt写,sbt也是刚学,各种变参不会用,又调试了一下午加晚上,终于还是写出来了
葱娘说SBT是傻逼树(SBTree),我特么觉得是超变态(SuperBT),唉。。这就是神犇与蒟蒻的差距啊。。
喜闻乐见的贴代码
/*
ID:WULALA
PROB:SBT bzoj1503
LANG:C++
*/
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <iostream>
#include <ctime>
#include <set>
#define N 100008
#define M
#define mod
#define mid(l,r) ((l+r) >> 1)
#define INF 0x7ffffff
using namespace std;
int n,MIN,delta,cnt,tot,root;
struct WULALA
{
int l,r,s,v;
}p[N];
void zig(int &x)
{
int y = p[x].l;
p[x].l = p[y].r;
p[y].r = x;
p[y].s = p[x].s;
p[x].s = p[p[x].l].s + p[p[x].r].s + 1;
x = y;
}
void zag(int &x)
{
int y = p[x].r;
p[x].r = p[y].l;
p[y].l = x;
p[y].s = p[x].s;
p[x].s = p[p[x].l].s + p[p[x].r].s + 1;
x = y;
}
void maintain(int &x,bool flag)
{
int l = p[x].l,r = p[x].r;
if (!flag)
{
if (p[p[l].l].s > p[r].s)
zig(x);
else if (p[p[l].r].s > p[r].s)
// zag(l),zig(x);
zag(p[x].l),zig(x);//x已改变,下同理;
else return ;
}
else
{
if (p[p[r].r].s > p[l].s)
zag(x);
else if (p[p[r].l].s > p[l].s)
zig(p[x].r),zag(x);
else return ;
}
// maintain(l,false);
// maintain(r,true);
maintain(p[x].l,false);
maintain(p[x].r,true);//x已改变
maintain(x,false);
maintain(x,true);
}
void insert(int &x,int k)
{
if (!x)
{
x = ++tot;
p[x].s = 1;
p[x].v = k;
}
else
{
p[x].s++;//!!
if (p[x].v > k) insert(p[x].l,k);
else insert(p[x].r,k);
maintain(x,k >= p[x].v);
}
}
int del(int &x)
{
int ans;
if (!x) return 0;
if (p[x].v + delta < MIN)
{
ans = p[p[x].l].s + 1 + del(p[x].r);
p[p[x].r].s = p[x].s - ans;
x = p[x].r;
}
else
{
ans = del(p[x].l);
p[x].s -= ans;
}
return ans;
}
int find(int x,int k)
{
if (p[p[x].r].s >= k) return find(p[x].r,k);
else if (p[p[x].r].s == k - 1) return p[x].v;
else return find(p[x].l,k - p[p[x].r].s - 1);
}
void debug()
{
printf("%d\n",root);
for (int i = cnt+1;i <= tot;i++)
{
printf("%d %d %d %d\n",p[i].l,p[i].r,p[i].s,p[i].v);
}
}
int main()
{
scanf("%d%d",&n,&MIN);
while (n--)
{
char c[1]; int k;
scanf("%s%d",c,&k);
if (c[0] == 'I' && k >= MIN)
insert(root,k-delta);
else if (c[0] == 'A')
delta += k;
else if (c[0] == 'S')
delta -= k,cnt += del(root);
else if (c[0] == 'F')
printf("%d\n",k <= p[root].s?find(root,k)+delta:-1);
// debug();
}
printf("%d\n",cnt);
return 0;
}