/*
f[i]表示i的父结点,
ch[i][0]表示i的左儿子,
ch[i][1]表示i的右儿子,
key[i]表示i的关键字(即结点i代表的那个数字),
cnt[i]表示i结点的关键字出现的次数(相当于权值),
size[i]表示包括i的这个子树的大小;
sz为整棵树的大小,root为整棵树的根。
*/
#include<bits/stdc++.h>
using namespace std;
const int MAXN=1000001;
int ch[MAXN][2],f[MAXN],size[MAXN],cnt[MAXN],key[MAXN];
int sz,root;
/*
【clear操作】:将当前点的各项值都清0(用于删除之后)
*/
inline void clear(int x)
{
ch[x][0]=ch[x][1]=f[x]=size[x]=cnt[x]=key[x]=0;
}
/*
【get操作】:判断当前点是它父结点的左儿子还是右儿子
*/
inline bool get(int x)
{
return ch[f[x]][1]==x;
}
/*
【update操作】:更新当前点的size值(用于发生修改之后)
*/
inline void update(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]];
}
}
inline void rotate(int x)
{
int p=f[x],pf=f[p],c=get(x);
ch[p][c]=ch[x][c^1];
f[ch[p][c]]=p;
ch[x][c^1]=p;
f[p]=x;
f[x]=pf;
if(pf)ch[pf][ch[pf][1]==p]=x;
update(p);
update(x);
}
inline void splay(int x)
{
for(int fa;fa=f[x];rotate(x))if(f[fa])rotate((get(x)==get(fa))?fa:x);
root=x;
}
inline void insert(int x)
{
if(root==0)
{
sz++;
ch[sz][0]=ch[sz][1]=f[sz]=0;
root=sz;
size[sz]=cnt[sz]=1;
key[sz]=x;
return;
}
int now=root,fa=0;
while(1)
{
if(x==key[now])
{
cnt[now]++;
update(now);
update(fa);
splay(now);
break;
}
fa=now;
now=ch[now][key[now]<x];
if(now==0)
{
sz++;
ch[sz][0]=ch[sz][1]=0;
f[sz]=fa;
size[sz]=cnt[sz]=1;
ch[fa][key[fa]<x]=sz;
key[sz]=x;
update(fa);
splay(sz);
break;
}
}
}
inline int find(int x)
{
int now=root,ans=0;
int j=0;
while(1)
{
if(j>sz)return 0;
if(x<key[now])now=ch[now][0];
else
{
ans+=(ch[now][0]?size[ch[now][0]]:0);
if(x==key[now])
{
splay(now);
return ans+1;
}
ans+=cnt[now];
now=ch[now][1];
}
j++;
}
}
inline int findx(int x)
{
int now=root;
while(1)
{
if(ch[now][0]&&x<=size[ch[now][0]])now=ch[now][0];
else
{
int tmp=(ch[now][0]?size[ch[now][0]]:0)+cnt[now];
if(x<=tmp)return key[now];
x-=tmp;
now=ch[now][1];
}
}
}
inline int pre(int x)
{
int now=ch[x][0];
while(ch[now][1])now=ch[now][1];
return now;
}
inline int suc(int x)
{
int now=ch[x][1];
while(ch[now][0])now=ch[now][0];
return now;
}
inline void del(int x)
{
int w=find(x);
if(cnt[root]>1)
{
cnt[root]--;
update(root);
return;
}
if(!ch[root][0]&&!ch[root][1])
{
clear(root);
root=0;
return;
}
if(!ch[root][0])
{
int pr=root;
root=ch[root][1];
f[root]=0;
clear(pr);
return;
}
else if(!ch[root][1])
{
int pr=root;
root=ch[root][0];
f[root]=0;
clear(pr);
return;
}
int pp=pre(root),pr=root;
splay(pp);
ch[root][1]=ch[pr][1];
f[ch[pr][1]]=root;
clear(pr);
update(root);
}
int main()
{
int n,opt,x;
scanf("%d",&n);
for(int i=1;i<=n;++i)
{
scanf("%d%d",&opt,&x);
switch(opt)
{
case 1:insert(x);break;
case 2:del(x);break;
case 3:printf("%d\n",find(x));break;
case 4:printf("%d\n",findx(x));break;
case 5:insert(x);printf("%d\n",pre(root)?key[pre(root)]:-1);del(x);break;
case 6:insert(x);printf("%d\n",suc(root)?key[suc(root)]:-1);del(x);break;
}
}
return 0;
}
题目:营业额统计(LOJ 10143)传送门
RE了一个点:
/*
f[i]表示i的父结点,
ch[i][0]表示i的左儿子,
ch[i][1]表示i的右儿子,
key[i]表示i的关键字(即结点i代表的那个数字),
cnt[i]表示i结点的关键字出现的次数(相当于权值),
size[i]表示包括i的这个子树的大小;
sz为整棵树的大小,root为整棵树的根。
*/
#include<bits/stdc++.h>
using namespace std;
const int MAXN=1000010;
int ch[MAXN][2],f[MAXN],size[MAXN],cnt[MAXN],key[MAXN];
bool flag[MAXN];
int sz,root;
/*
【clear操作】:将当前点的各项值都清0(用于删除之后)
*/
inline void clear(int x)
{
ch[x][0]=ch[x][1]=f[x]=size[x]=cnt[x]=key[x]=0;
}
/*
【get操作】:判断当前点是它父结点的左儿子还是右儿子
*/
inline bool get(int x)
{
return ch[f[x]][1]==x;
}
/*
【update操作】:更新当前点的size值(用于发生修改之后)
*/
inline void update(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]];
}
}
inline void rotate(int x)
{
int p=f[x],pf=f[p],c=get(x);
ch[p][c]=ch[x][c^1];
f[ch[p][c]]=p;
ch[x][c^1]=p;
f[p]=x;
f[x]=pf;
if(pf)ch[pf][ch[pf][1]==p]=x;
update(p);
update(x);
}
inline void splay(int x)
{
for(int fa;fa=f[x];rotate(x))if(f[fa])rotate((get(x)==get(fa))?fa:x);
root=x;
}
inline void insert(int x)
{
if(root==0)
{
sz++;
ch[sz][0]=ch[sz][1]=f[sz]=0;
root=sz;
size[sz]=cnt[sz]=1;
key[sz]=x;
return;
}
int now=root,fa=0;
while(1)
{
if(x==key[now])
{
cnt[now]++;
update(now);
update(fa);
splay(now);
flag[x]=true;
break;
}
fa=now;
now=ch[now][key[now]<x];
if(now==0)
{
sz++;
ch[sz][0]=ch[sz][1]=0;
f[sz]=fa;
size[sz]=cnt[sz]=1;
ch[fa][key[fa]<x]=sz;
key[sz]=x;
update(fa);
splay(sz);
break;
}
}
}
inline int find(int x)
{
int now=root,ans=0;
int j=0;
while(1)
{
if(j>sz)return 0;
if(x<key[now])now=ch[now][0];
else
{
ans+=(ch[now][0]?size[ch[now][0]]:0);
if(x==key[now])
{
splay(now);
return ans+1;
}
ans+=cnt[now];
now=ch[now][1];
}
j++;
}
}
inline int findx(int x)
{
int now=root;
while(1)
{
if(ch[now][0]&&x<=size[ch[now][0]])now=ch[now][0];
else
{
int tmp=(ch[now][0]?size[ch[now][0]]:0)+cnt[now];
if(x<=tmp)return key[now];
x-=tmp;
now=ch[now][1];
}
}
}
inline int pre(int x)
{
int now=ch[x][0];
while(ch[now][1])now=ch[now][1];
return now;
}
inline int suc(int x)
{
int now=ch[x][1];
while(ch[now][0])now=ch[now][0];
return now;
}
inline void del(int x)
{
int w=find(x);
if(cnt[root]>1)
{
cnt[root]--;
update(root);
return;
}
if(!ch[root][0]&&!ch[root][1])
{
clear(root);
root=0;
return;
}
if(!ch[root][0])
{
int pr=root;
root=ch[root][1];
f[root]=0;
clear(pr);
return;
}
else if(!ch[root][1])
{
int pr=root;
root=ch[root][0];
f[root]=0;
clear(pr);
return;
}
int pp=pre(root),pr=root;
splay(pp);
ch[root][1]=ch[pr][1];
f[ch[pr][1]]=root;
clear(pr);
update(root);
}
int main()
{
int n,x;
int ans=0;
scanf("%d",&n);
memset(flag,false,sizeof(flag));
scanf("%d",&x);
insert(x);
ans+=x;
for(int i=2;i<=n;++i)
{
scanf("%d",&x);
insert(x);
if(flag[x])continue;
int a=pre(root),b=suc(root);
if(a&&b)ans+=min(x-key[a],key[b]-x);
else if(a)ans+=x-key[a];
else if(b)ans+=key[b]-x;
}
printf("%d",ans);
return 0;
}