题意:有三种操作:1.将权值为p名称为k的顾客加入队列 2.从队列中取出权值较高的顾客,并输出 3.从队列中取出权值较低的顾客并输出
题解:用splay维护权值,再询问
AC代码:
#include<stdio.h>
#include<string.h>
#include<map>
using namespace std;
#define MAXN 1000005 //节点数
int ch[MAXN][2],f[MAXN],cnt[MAXN],key[MAXN],size[MAXN];
int sz=0,root=0;
int newnode(int fa,int v)
{
sz++;
ch[sz][0]=ch[sz][1]=0;
f[sz]=fa;key[sz]=v;
size[sz]=cnt[sz]=1;
return sz;
}
void clear(int x)
{
ch[x][0]=ch[x][1]=f[x]=cnt[x]=key[x]=size[x]=0;
}
int get(int x)//得到x是其父亲的左儿子还是右儿子
{
return ch[f[x]][1]==x;
}
void up(int x)
{
if(x)
{
size[x]=cnt[x];
if(ch[x][0])size[x]+=size[ch[x][0]];
if(ch[x][1])size[x]+=size[ch[x][1]];
}
}
void rotate(int x)
{
int old=f[x],oldf=f[old],which=get(x);
ch[old][which]=ch[x][which^1];f[ch[old][which]]=old;
f[old]=x;ch[x][which^1]=old;
f[x]=oldf;
if(oldf)ch[oldf][ch[oldf][1]==old]=x;
up(old);up(x);
}
void splay(int x,int goal)//伸展
{
for(int fa;(fa=f[x]);rotate(x))
if(f[fa]!=goal)
rotate((get(x)==get(fa)?fa:x));
if(goal==0)root=x;
}
void insert(int v)
{
if(root==0)
{
root=newnode(0,v);
return;
}
int now=root,fa=0;
while(1)
{
if (key[now]==v)
{
cnt[now]++;
up(now);up(fa);
splay(now,0);break;
}
fa=now;
now=ch[now][key[now]<v];
if(now==0)
{
int newroot=newnode(fa,v);
ch[fa][key[fa]<v]=newroot;
up(fa);
splay(sz,0);
break;
}
}
}
int find(int v)//查询v的排名
{
int ans=0,now=root;
while(1)
{
if(v<key[now])
now=ch[now][0];
else
{
ans+=(ch[now][0]?size[ch[now][0]]:0);
if(v==key[now])
{
splay(now,0);
return ans+1;
}
ans+=cnt[now];
now=ch[now][1];
}
}
}
int findx(int x)//查询第x小权值是多少
{
int now=root;
while(1)
{
if(ch[now][0]&&x<=size[ch[now][0]])
now=ch[now][0];
else
{
int temp=(ch[now][0]?size[ch[now][0]]:0)+cnt[now];
if(x<=temp)return key[now];
x-=temp;now=ch[now][1];
}
}
}
int pre()
{
int now=ch[root][0];
while(ch[now][1])now=ch[now][1];
return now;
}
int next()
{
int now=ch[root][1];
while(ch[now][0])now=ch[now][0];
return now;
}
void del(int x)//删除某权值的点
{
int whatever=find(x);
if (cnt[root]>1) {cnt[root]--;return;}
//自由一个点
if (!ch[root][0]&&!ch[root][1]) {clear(root);root=0;return;}
//只有一个儿子
if (!ch[root][0])
{
int oldroot=root;root=ch[root][1];f[root]=0;clear(oldroot);return;
}
else if (!ch[root][1])
{
int oldroot=root;root=ch[root][0];f[root]=0;clear(oldroot);return;
}
//两个儿子
int leftbig=pre(),oldroot=root;
splay(leftbig,0);
f[ch[oldroot][1]]=root;
ch[root][1]=ch[oldroot][1];
clear(oldroot);
up(root);
return;
}
map<int,int>mp;
int main()
{
int op;
while(~scanf("%d",&op))
{
if(op==0)break;
if(op==1)
{
int k,v;
scanf("%d%d",&k,&v);
insert(v);
mp[v]=k;
}
if(op==2)
{
if(size[root]==0)
{
printf("0\n");
continue;
}
int v=findx(size[root]);
printf("%d\n",mp[v]);
del(v);
}
if(op==3)
{
if(size[root]==0)
{
printf("0\n");
continue;
}
int v=findx(1);
printf("%d\n",mp[v]);
del(v);
}
}
}
splay模板:
#define MAXN 100005 //节点数
int ch[MAXN][2],f[MAXN],cnt[MAXN],key[MAXN],size[MAXN];
int sz=0,root=0;
int newnode(int fa,int v)
{
sz++;
ch[sz][0]=ch[sz][1]=0;
f[sz]=fa;key[sz]=v;
size[sz]=cnt[sz]=1;
return sz;
}
void clear(int x)
{
ch[x][0]=ch[x][1]=f[x]=cnt[x]=key[x]=size[x]=0;
}
int get(int x)//得到x是其父亲的左儿子还是右儿子
{
return ch[f[x]][1]==x;
}
void up(int x)
{
if(x)
{
size[x]=cnt[x];
if(ch[x][0])size[x]+=size[ch[x][0]];
if(ch[x][1])size[x]+=size[ch[x][1]];
}
}
void rotate(int x)
{
int old=f[x],oldf=f[old],which=get(x);
ch[old][which]=ch[x][which^1];f[ch[old][which]]=old;
f[old]=x;ch[x][which^1]=old;
f[x]=oldf;
if(oldf)ch[oldf][ch[oldf][1]==old]=x;
up(old);up(x);
}
void splay(int x,int goal)//伸展
{
for(int fa;(fa=f[x]);rotate(x))
if(f[fa]!=goal)
rotate((get(x)==get(fa)?fa:x));
if(goal==0)root=x;
}
void insert(int v)
{
if(root==0)
{
root=newnode(0,v);
return;
}
int now=root,fa=0;
while(1)
{
if (key[now]==v)
{
cnt[now]++;
up(now);up(fa);
splay(now,0);break;
}
fa=now;
now=ch[now][key[now]<v];
if(now==0)
{
int newroot=newnode(fa,v);
ch[fa][key[fa]<v]=newroot;
up(fa);
splay(sz,0);
break;
}
}
}
int find(int v)//查询v的排名
{
int ans=0,now=root;
while(1)
{
if(v<key[now])
now=ch[now][0];
else
{
ans+=(ch[now][0]?size[ch[now][0]]:0);
if(v==key[now])
{
splay(now,0);
return ans+1;
}
ans+=cnt[now];
now=ch[now][1];
}
}
}
int findx(int x)//查询第x小权值是多少
{
int now=root;
while(1)
{
if(ch[now][0]&&x<=size[ch[now][0]])
now=ch[now][0];
else
{
int temp=(ch[now][0]?size[ch[now][0]]:0)+cnt[now];
if(x<=temp)return key[now];
x-=temp;now=ch[now][1];
}
}
}
int pre()
{
int now=ch[root][0];
while(ch[now][1])now=ch[now][1];
return now;
}
int next()
{
int now=ch[root][1];
while(ch[now][0])now=ch[now][0];
return now;
}
void del(int x)//删除某权值的点
{
int whatever=find(x);
if (cnt[root]>1) {cnt[root]--;return;}
//自由一个点
if (!ch[root][0]&&!ch[root][1]) {clear(root);root=0;return;}
//只有一个儿子
if (!ch[root][0])
{
int oldroot=root;root=ch[root][1];f[root]=0;clear(oldroot);return;
}
else if (!ch[root][1])
{
int oldroot=root;root=ch[root][0];f[root]=0;clear(oldroot);return;
}
//两个儿子
int leftbig=pre(),oldroot=root;
splay(leftbig,0);
f[ch[oldroot][1]]=root;
ch[root][1]=ch[oldroot][1];
clear(oldroot);
up(root);
return;
}