[关键字]:平衡树
[题目大意]:http://www.zybbs.org/JudgeOnline/problem.php?id=1208
//=====================================================================================================
[分析]:其实人买狗和狗挑人是一样的,只是狗多时就是维护一个以狗为节点的treap,然后根据人的需求去查找;人多时treap存储的节点变为人再进行操作。
[代码]:
1 #include<iostream>
2 #include<cstdio>
3 #include<cstdlib>
4 #include<algorithm>
5 #include<cstring>
6 #include<ctime>
7 using namespace std;
8
9 int n,m,tn,ans,sum,root,kind;
10 int L[90000],R[90000],V[90000],W[90000];
11
12 int Right_Rotate(int &t)
13 {
14 int k=L[t];
15 L[t]=R[k];
16 R[k]=t;
17 t=k;
18 return 0;
19 }
20
21 int Left_Rotate(int &t)
22 {
23 int k=R[t];
24 R[t]=L[k];
25 L[k]=t;
26 t=k;
27 return 0;
28 }
29
30 int Insert(int &t,int v)
31 {
32 if (t)
33 if (v<V[t])
34 {
35 Insert(L[t],v);
36 if (W[t]>W[L[t]]) Right_Rotate(t);
37 }
38 else
39 {
40 Insert(R[t],v);
41 if (W[t]>W[R[t]]) Left_Rotate(t);
42 }
43 else
44 {
45 t=++tn;
46 V[t]=v;
47 L[t]=R[t]=0;
48 W[t]=(rand()%85000)+1;
49 }
50 return 0;
51 }
52
53 int Find(int t,int v)
54 {
55 while (t && v!=V[t]) t=v<V[t]?Find(L[t],v):Find(R[t],v);
56 return t;
57 }
58
59 int Delete(int &t,int v)
60 {
61 if (v==V[t] || v<V[t] && !L[t] || v> V[t] && !R[t])
62 {
63 int temp=V[t];
64 if (!L[t] || !R[t]) t=L[t]+R[t];
65 else V[t]=Delete(L[t],V[t]+1);
66 return temp;
67 }
68 else if (v<V[t]) Delete(L[t],v);
69 else return Delete(R[t],v);
70 }
71
72 int Pred(int t,int v)
73 {
74 if (!t) return v;
75 if (v<=V[t]) return Pred(L[t],v);
76 else
77 {
78 int temp=Pred(R[t],v);
79 return v==temp?V[t]:temp;
80 }
81 }
82
83 int Succ(int t,int v)
84 {
85 if (!t) return v;
86 if (v>=V[t]) return Succ(R[t],v);
87 else
88 {
89 int temp=Succ(L[t],v);
90 return v==temp?V[t]:temp;
91 }
92 }
93
94 int main()
95 {
96 freopen("pet.in","r",stdin);
97 freopen("pet.out","w",stdout);
98 scanf("%d",&n);
99 srand((unsigned)time(NULL));
100 int a,b;
101 ans=tn=root=sum=kind=0;
102 for (int i=1;i<=n;i++)
103 {
104 scanf("%d%d",&a,&b);
105 if (!sum || kind==a) kind=a,Insert(root,b),sum++;
106 else
107 if (Find(root,b)) Delete(root,b),sum--;
108 else
109 {
110 int x=Pred(root,b);
111 int y=Succ(root,b);
112 if (x==b || y==b) x=x+y-b;
113 else if (b-x>y-b) x=y;
114 Delete(root,x);
115 sum--;
116 ans+=abs(x-b);
117 if (ans>=1000000) ans%=1000000;
118 }
119 }
120 printf("%d\n",ans);
121 //system("pause");
122 return 0;
123 }
(不知为什么在BZOJ上RE但在本地cena上AC)
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
using namespace std;
int n,ans,sum,root,tn,kind;
int S[90000],L[90000],R[90000],V[90000];
int Right_Rotate(int &t)
{
int k=L[t];
L[t]=R[k];
R[k]=t;
S[k]=S[t];
S[t]=S[L[t]]+S[R[t]]+1;
t=k;
return 0;
}
int Left_Rotate(int &t)
{
int k=R[t];
R[t]=L[k];
L[k]=t;
S[k]=S[t];
S[t]=S[L[t]]+S[R[t]]+1;
t=k;
return 0;
}
int Maintain(int &t,bool flag)
{
if (flag)
{
if (S[L[R[t]]]>S[L[t]]) Right_Rotate(R[t]),Left_Rotate(t); else
if (S[R[R[t]]]>S[L[t]]) Left_Rotate(t); else return 0;
}
else
{
if (S[L[L[t]]]>S[R[t]]) Right_Rotate(t); else
if (S[R[L[t]]]>S[R[t]]) Left_Rotate(L[t]),Right_Rotate(t); else return 0;
}
Maintain(L[t],0);
Maintain(R[t],1);
Maintain(t,1);
Maintain(t,0);
return 0;
}
int Insert(int &t,int v)
{
if (t)
{
S[t]++;
if (v<V[t]) Insert(L[t],v); else Insert(R[t],v);
Maintain(t,v>=V[t]);
}
else
{
S[t=++tn]=1;
V[t]=v;
L[t]=R[t]=0;
}
return 0;
}
int Find(int t,int v)
{
while (t && v!=V[t]) t=v<V[t]?Find(L[t],v):Find(R[t],v);
return t;
}
int Delete(int &t,int v)
{
S[t]--;
if (v==V[t] || v<V[t] && !L[t] || v>V[t] && !R[t])
{
int temp=V[t];
if (!L[t] || !R[t]) t=L[t]+R[t];
else V[t]=Delete(L[t],V[t]+1);
return temp;
}
else if (v<V[t]) return Delete(L[t],v);
else return Delete(R[t],v);
}
int Pred(int t,int v)
{
if (!t) return v;
if (v<=V[t]) return Pred(L[t],v);
else
{
int temp=Pred(R[t],v);
return v==temp?V[t]:temp;
}
}
int Succ(int t,int v)
{
if (!t) return v;
if (v>=V[t]) Succ(R[t],v);
else
{
int temp=Succ(L[t],v);
return v==temp?V[t]:temp;
}
}
int main()
{
scanf("%d",&n);
tn=sum=ans=root=kind=S[0]=0;
for (int i=1;i<=n;i++)
{
int x,y,a,b;
scanf("%d%d",&a,&b);
if (!sum || kind==a) kind=a,Insert(root,b),sum++;
else
if (Find(root,b)) Delete(root,b),sum--;
else
{
int x=Pred(root,b);
int y=Succ(root,b);
if (x==b || y==b) x=x+y-b;
else if (b-x>y-b) x=y;
ans+=abs(b-x);
if (ans>=1000000) ans%=1000000;
Delete(root,x);
sum--;
}
}
printf("%d\n",ans);
system("pause");
return 0;
}
(本地和BZOJ都AC)
这题还可以直接用STL中的set做
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<set>
using namespace std;
int n,x,y,ans=0,kind=0;
set<int> s;
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;++i)
{
scanf("%d%d",&x,&y);
if (x==kind || s.empty()) kind=x,s.insert(y);
else
{
pair<set<int>::iterator,set<int>::iterator>p=s.equal_range(y);
if (p.first==p.second)
{
if (p.first!=s.begin()) p.first--;
if (abs(y-*p.first)<=abs(y-*p.second)) ans+=abs(y-*p.first),s.erase(p.first);
else ans+=abs(y-*p.second),s.erase(p.second);
}
else s.erase(p.first);
ans%=1000000;
}
}
printf("%d\n",ans);
system("pause");
return 0;
}