学完模版后就开始在COGS上刷题了,但一直没有整理在一起,发此文记录一下(操作名称参见 treap 模版 http://blog.youkuaiyun.com/lcomyn/article/details/42582627)
COGS 62 HNOI 宠物收养所
题意很简单,大致就是求前驱和后继中较接近x值的点,所需操作insert(包括tlr,trr,下同),delete,tpred,tsucc;需要记录一下宠物和主人的数量(这题第一眼我还以为要建两棵平衡树) code:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<ctime>
using namespace std;
struct treap_node{
treap_node *left,*right;
int val,fix,wgt,size;
treap_node(int val): val(val) {left=right=NULL; wgt=size=1; fix=rand();}
int lsize()
{
if (left)
return left->size;
else
return 0;
}
int rsize()
{
if (right)
return right->size;
else
return 0;
}
void Maintain()
{
size=wgt;
size+=lsize()+rsize();
}
};
treap_node *root;
int n;
void tlr(treap_node *&a)
{
treap_node *b=a->right;
a->right=b->left;
b->left=a;
a->Maintain();
b->Maintain();
a=b;
}
void trr(treap_node *&a)
{
treap_node *b=a->left;
a->left=b->right;
b->right=a;
a->Maintain();
b->Maintain();
a=b;
}
void insert(treap_node *&p,int value)
{
if (!p)
p=new treap_node(value);
else
{
if (value==p->val)
p->wgt++;
if (value<p->val)
{
insert(p->left,value);
if (p->left->fix<p->fix)
trr(p);
}
if (value>p->val)
{
insert(p->right,value);
if (p->right->fix<p->fix)
tlr(p);
}
}
p->Maintain();
}
void del(treap_node *&p,int value)
{
if (p->val==value)
{
if (p->wgt==1)
{
if (!p->left||!p->right)
{
if (!p->left)
p=p->right;
else
p=p->left;
}
else
{
if (p->left->fix<p->right->fix)
{
trr(p);
del(p->right,value);
}
else
{
tlr(p);
del(p->left,value);
}
}
}
else
p->wgt--;
}
else
{
if (value<p->val)
del(p->left,value);
else
del(p->right,value);
}
if (p!=NULL) p->Maintain();
}
treap_node* tpred(treap_node *&p,int value,treap_node* best)
{
if (!p) return best;
if (p->val<=value)
return tpred(p->right,value,p);
else
return tpred(p->left,value,best);
}
treap_node* tsucc(treap_node *&p,int value,treap_node* best)
{
if (!p) return best;
if (p->val>=value)
return tsucc(p->left,value,p);
else
return tsucc(p->right,value,best);
}
int main()
{
int i,kind,a,n0,n1;
int sum,x,y,t;
freopen("pet.in","r",stdin);
freopen("pet.out","w",stdout);
treap_node *t1,*t2;
treap_node *null=NULL;
n0=0; n1=0; sum=0;
scanf("%d",&n);
for (i=1;i<=n;++i)
{
scanf("%d%d",&kind,&a);
if (kind==0)
{
t1=t2=null; x=y=2100000000;
if (n1!=0)
{
t1=tpred(root,a,null);
t2=tsucc(root,a,null);
if (t1)
x=a-t1->val;
if (t2)
y=t2->val-a;
t=min(x,y);
sum=(sum+t)%1000000;
if (x<=y)
del(root,t1->val);
else
del(root,t2->val);
n1--;
}
else
{
n0++;
insert(root,a);
}
}
if (kind==1)
{
t1=t2=null; x=y=2100000000;
if (n0!=0)
{
t1=tpred(root,a,null);
t2=tsucc(root,a,null);
if (t1)
x=a-t1->val;
if (t2)
y=t2->val-a;
t=min(x,y);
sum=(sum+t)%1000000;
if (x<=y)
del(root,t1->val);
else
del(root,t2->val);
n0--;
}
else
{
n1++;
insert(root,a);
}
}
}
printf("%d\n",sum%1000000);
fclose(stdin);
fclose(stdout);
}
COGS NOI 2004 郁闷的出纳员
题意很简单,但是个人觉得我的想法可能时间复杂度稍高(我用一个数组记录了修改值时低于平均工资的序号,然后一并删除),所需操作,insert,delete(已知序号),kth,整体修改(chg) code:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<ctime>
using namespace std;
struct treap_node{
treap_node *left,*right;
int val,fix,wgt,size;
treap_node(int val): val(val) {left=right=NULL; size=wgt=1; fix=rand(); }
int lsize()
{
if (left)
return left->size;
else
return 0;
}
int rsize()
{
if (right)
return right->size;
else
return 0;
}
void Maintain()
{
size=wgt;
size+=lsize()+rsize();
}
};
treap_node *root,*delt[100001];
int n,minn,size,i;
void tlr(treap_node *&a)
{
treap_node *b=a->right;
a->right=b->left;
b->left=a;
a->Maintain();
b->Maintain();
a=b;
}
void trr(treap_node *&a)
{
treap_node *b=a->left;
a->left=b->right;
b->right=a;
a->Maintain();
b->Maintain();
a=b;
}
void insert(treap_node *&p,int value)
{
if (!p)
p=new treap_node(value);
else
{
if (value==p->val)
p->wgt++;
if (value<p->val)
{
insert(p->left,value);
if (p->left->fix<p->fix)
trr(p);
}
if (value>p->val)
{
insert(p->right,value);
if (p->right->fix<p->fix)
tlr(p);
}
}
p->Maintain();
}
treap_node* kth(treap_node *&p,int k)
{
if (k<p->lsize()+1)
return kth(p->left,k);
else
if (k>p->lsize()+p->wgt)
return kth(p->right,k-p->lsize()-p->wgt);
else
return p;
}
void del(treap_node *&p,treap_node *&d)
{
if (p==d)
{
if (p->wgt==1)
{
if (!p->left||!p->right)
{
if (!p->left)
p=p->right;
else
p=p->left;
}
else
{
if (p->left->fix<p->right->fix)
{
trr(p);
del(p->right,d);
}
else
{
tlr(p);
del(p->left,d);
}
}
}
else
p->wgt--;
}
else
{
if (d->val<p->val)
del(p->left,d);
if (d->val>p->val)
del(p->right,d);
}
if (p!=NULL) p->Maintain();
}
void chg(treap_node *&p,int a)
{
int i;
p->val+=a;
if (p->val<minn)
{
for (i=1;i<=p->wgt;++i)
{
size++;
delt[size]=p;
}
}
if (p->left)
chg(p->left,a);
if (p->right)
chg(p->right,a);
if (p!=NULL)
p->Maintain();
}
int main()
{
int a,j,m,z;
char c;
freopen("cashier.in","r",stdin);
freopen("cashier.out","w",stdout);
treap_node *null=NULL;
scanf("%d%d",&n,&minn);
m=0; z=0;
for (i=1;i<=n;++i)
{
scanf("%*c%c%d",&c,&a);
if (c=='I'&&a>=minn)
{
m++;
insert(root,a);
}
if (c=='A'||c=='S')
{
size=0;
memset(delt,0,sizeof(delt));
if (c=='S')
a=-a;
chg(root,a);
m-=size; z+=size;
for (j=1;j<=size;++j)
del(root,delt[j]);
}
if (c=='F')
{
treap_node *t;
if (a>m)
printf("-1\n");
else
{
t=kth(root,m-a+1);
if (t)
printf("%d\n",t->val);
}
}
}
printf("%d\n",z);
fclose(stdin);
fclose(stdout);
}
COGS 516 求和
题目较难,需要搜索树上结点,不过仔细思考还是可以想得出来的,所需操作insert,搜索(search,当此结点值>=k时,继续搜索右子树,反之搜索左子树)code:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<ctime>
using namespace std;
struct treap_node{
treap_node *left,*right;
int val;
int fix,wgt,size;
treap_node(int val):val(val) {left=right=NULL; wgt=size=1; fix=rand(); }
int lsize()
{
if (left)
return left->size;
else
return 0;
}
int rsize()
{
if (right)
return right->size;
else
return 0;
}
void Maintain()
{
size=wgt;
size+=lsize()+rsize();
}
};
treap_node *root;
int n;
int P,k;
int a[100001];
void tlr(treap_node *&a)
{
treap_node *b=a->right;
a->right=b->left;
b->left=a;
a->Maintain();
b->Maintain();
a=b;
}
void trr(treap_node *&a)
{
treap_node *b=a->left;
a->left=b->right;
b->right=a;
a->Maintain();
b->Maintain();
a=b;
}
void insert(treap_node *&p,int value)
{
if (!p)
p=new treap_node(value);
else
{
if (p->val==value)
p->wgt++;
if (value<p->val)
{
insert(p->left,value);
if (p->left->fix<p->fix)
trr(p);
}
if (value>p->val)
{
insert(p->right,value);
if (p->right->fix<p->fix)
tlr(p);
}
}
p->Maintain();
}
int search(treap_node *&p,int value,int best)
{
if (!p) return best;
if ((value-p->val+P)%P>=k)
return search(p->right,value,min(best,(value-p->val+P)%P));
else
return search(p->left,value,best);
}
int main()
{
int i,j,t,ans;
int x;
treap_node *null=NULL;
freopen("suma.in","r",stdin);
freopen("suma.out","w",stdout);
ans=2100000000;
scanf("%d%d%d",&n,&k,&P);
insert(root,0);
for (i=1;i<=n;++i)
{
x=0;
scanf("%lld",&x);
x=x%P;
a[i]=(a[i-1]+x)%P;
ans=min(ans,search(root,a[i],2100000000));
insert(root,a[i]);
}
printf("%d\n",ans);
fclose(stdin);
fclose(stdout);
}
COGS 1431 HNOI 永无乡
比较综合的题目,并查集+Treap+启发式合并,学会了合并操作,所需操作insert,merge,kth code:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<ctime>
#include<cstdlib>
using namespace std;
struct treap_node{
treap_node *left,*right;
int val,fix,wgt,size;
treap_node(int val): val(val) {left=right=NULL; wgt=size=1; fix=rand();}
int lsize()
{
if (left)
return left->size;
else
return 0;
}
int rsize()
{
if (right)
return right->size;
else
return 0;
}
void Maintain()
{
size=wgt;
size+=lsize()+rsize();
}
};
treap_node *root[100001];
int n,m,q,father[100001],a[100001],f[100001];
int find(int x)
{
if (x!=father[x])
father[x]=find(father[x]);
return father[x];
}
void tlr(treap_node *&a)
{
treap_node *b=a->right;
a->right=b->left;
b->left=a;
a->Maintain();
b->Maintain();
a=b;
}
void trr(treap_node *&a)
{
treap_node *b=a->left;
a->left=b->right;
b->right=a;
a->Maintain();
b->Maintain();
a=b;
}
void insert(treap_node *&p,int value)
{
if (!p)
p=new treap_node(value);
else
{
if (p->val==value)
p->wgt++;
if (value<p->val)
{
insert(p->left,value);
if (p->left->fix<p->fix)
trr(p);
}
if (value>p->val)
{
insert(p->right,value);
if (p->right->fix<p->fix)
tlr(p);
}
}
p->Maintain();
}
void merge(treap_node *&a,treap_node *&b)
{
if (a->left) merge(a->left,b);
if (a->right) merge(a->right,b);
insert(b,a->val);
}
treap_node *kth(treap_node *&p,int k)
{
if (k<p->lsize()+1)
return kth(p->left,k);
else
if (k>p->lsize()+p->wgt)
return kth(p->right,k-p->lsize()-p->wgt);
else
return p;
}
int main()
{
int i,x,num,y,r1,r2;
char ch;
treap_node *null=NULL,*t;
freopen("bzoj_2733.in","r",stdin);
freopen("bzoj_2733.out","w",stdout);
scanf("%d%d",&n,&m);
for (i=1;i<=n;++i)
{
scanf("%d",&x);
a[i]=x;
father[i]=i;
f[x]=i;
insert(root[i],x);
}
for (i=1;i<=m;++i)
{
scanf("%d%d",&x,&y);
r1=find(x); r2=find(y);
if (r1!=r2)
{
if (root[r1]->size<=root[r2]->size)
{
father[r1]=r2;
merge(root[r1],root[r2]);
root[r1]==null;
}
else
{
father[r2]=r1;
merge(root[r2],root[r1]);
root[r2]=null;
}
}
}
scanf("%d",&q);
for (i=1;i<=q;++i)
{
while(true)
{
scanf("%c",&ch);
if (ch=='B'||ch=='Q') break;
}
scanf("%d%d",&x,&y);
r1=find(x);
if (ch=='Q')
{
if (y>root[r1]->size)
printf("-1\n");
else
{
t=kth(root[r1],y);
printf("%d\n",f[t->val]);
}
}
if (ch=='B')
{
r1=find(x); r2=find(y);
if (root[r1]->size<=root[r2]->size)
{
father[r1]=r2;
merge(root[r1],root[r2]);
root[r1]=null;
}
else
{
father[r2]=r1;
merge(root[r2],root[r1]);
root[r2]=null;
}
}
}
fclose(stdin);
fclose(stdout);
}
COGS 1533 营业额统计
模版题,所需操作insert,tpred,tsucc(严重吐槽此题需要自己补0) code:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<ctime>
#include<cmath>
using namespace std;
struct treap_node{
treap_node *left,*right;
int val,fix,wgt,size;
treap_node(int val):val(val) {left=right=NULL; wgt=size=1; fix=rand(); }
int lsize()
{
if (left)
return left->size;
else
return 0;
}
int rsize()
{
if (right)
return right->size;
else
return 0;
}
void Maintain()
{
size=wgt;
size+=lsize()+rsize();
}
};
treap_node *root;
int n;
void tlr(treap_node *&a)
{
treap_node *b=a->right;
a->right=b->left;
b->left=a;
a->Maintain();
b->Maintain();
a=b;
}
void trr(treap_node *&a)
{
treap_node *b=a->left;
a->left=b->right;
b->right=a;
a->Maintain();
b->Maintain();
a=b;
}
void insert(treap_node *&p,int value)
{
if (!p)
p=new treap_node(value);
else
{
if (value==p->val)
p->wgt++;
if (value<p->val)
{
insert(p->left,value);
if (p->left->fix<p->fix)
trr(p);
}
if (value>p->val)
{
insert(p->right,value);
if (p->right->fix<p->fix)
tlr(p);
}
}
p->Maintain();
}
treap_node* tpred(treap_node *&p,int value,treap_node *&best)
{
if (!p) return best;
if (p->val<=value)
return tpred(p->right,value,p);
else
return tpred(p->left,value,best);
}
treap_node* tsucc(treap_node *&p,int value,treap_node *&best)
{
if (!p) return best;
if (p->val>=value)
return tsucc(p->left,value,p);
else
return tsucc(p->right,value,best);
}
int main()
{
int i,ans,sum,x;
freopen("turnover.in","r",stdin);
freopen("turnover.out","w",stdout);
sum=0;
treap_node *temp;
treap_node *null=NULL;
scanf("%d",&n);
for (i=1;i<=n;++i)
{
if(scanf("%d",&x)==EOF)
x=0;
ans=2100000000;
temp=tpred(root,x,null);
if (temp)
ans=min(ans,x-temp->val);
temp=tsucc(root,x,null);
if (temp)
ans=min(ans,temp->val-x);
if (i==1) ans=x;
sum+=ans;
insert(root,x);
}
printf("%d\n",sum);
fclose(stdin);
fclose(stdout);
}
BZOJ 1058 报表统计
一道不简单的平衡树(神犇请无视),对于MIN_SORT_GAP我们可以建立一棵平衡树,每插入一个节点,就查询一个数的前驱、后继,取最小值与之前的最小值取min。
对于MIN_GAP,由于插入一个节点,破坏了一对差值关系,新建了两对差值关系,放在小根堆中,取堆根中元素即可。code:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<ctime>
#include<cmath>
#include<algorithm>
#include<cstring>
using namespace std;
struct treap_node{
treap_node *left,*right;
int val,wgt,size,fix;
treap_node(int val): val(val) {left=right=NULL; wgt=size=1; fix=rand();}
int lsize()
{
if (left)
return left->size;
else
return 0;
}
int rsize()
{
if (right)
return right->size;
else
return 0;
}
void Maintain()
{
size=wgt;
size+=lsize()+rsize();
}
};
treap_node *roota;
int a[500001]={0},en[500001]={0},n,m,v[1500001]={0},heap[1500001]={0},pos[1500001]={0},f[500001]={0},tot;
void tlr(treap_node *&a)
{
treap_node *b=a->right;
a->right=b->left;
b->left=a;
a->Maintain();
b->Maintain();
a=b;
}
void trr(treap_node *&a)
{
treap_node *b=a->left;
a->left=b->right;
b->right=a;
a->Maintain();
b->Maintain();
a=b;
}
void insert(treap_node *&p,int value)
{
if (!p) p=new treap_node(value);
else
{
if (value==p->val)
p->wgt++;
if (value<p->val)
{
insert(p->left,value);
if (p->left->fix<p->fix)
trr(p);
}
if (value>p->val)
{
insert(p->right,value);
if (p->right->fix<p->fix)
tlr(p);
}
}
p->Maintain();
}
treap_node *tpred(treap_node *&p,int value,treap_node *best)
{
if (!p) return best;
else
if (p->val<=value)
return tpred(p->right,value,p);
else
return tpred(p->left,value,best);
}
treap_node *tsucc(treap_node *&p,int value,treap_node *best)
{
if (!p) return best;
else
if (p->val>=value)
return tsucc(p->left,value,p);
else
return tsucc(p->right,value,best);
}
void up(int x)
{
int i;
while (x>1)
{
i=x/2;
if (v[heap[x]]<v[heap[i]])
{
swap(pos[heap[x]],pos[heap[i]]);
swap(heap[x],heap[i]);
}
x=i;
}
}
void down(int x)
{
int i;
while (x*2<=tot)
{
if (x*2==tot||(x*2<tot&&v[heap[x*2]]<v[heap[x*2+1]])) i=x*2;
else i=x*2+1;
if (v[heap[x]]>v[heap[i]])
{
swap(pos[heap[x]],pos[heap[i]]);
swap(heap[x],heap[i]);
}
x=i;
}
}
int main()
{
treap_node *null=NULL,*t;
char s[50];
int i,j,x,minn=2100000000,num,mint;
tot=0;
scanf("%d%d",&n,&m);
for (i=1;i<=n;++i)
{
scanf("%d",&a[i]);
en[i]=a[i];
if (i>1)
{++tot; v[tot]=abs(a[i]-a[i-1]);pos[tot]=tot; heap[tot]=tot; f[i-1]=tot; up(tot);}
t=tpred(roota,a[i],null);
if (t!=NULL)
minn=min(minn,a[i]-t->val);
t=tsucc(roota,a[i],null);
if (t!=NULL)
minn=min(minn,t->val-a[i]);
insert(roota,a[i]);
}
mint=v[heap[1]];
for (i=1;i<=m;++i)
{
scanf("%s",&s);
if (s[0]=='I')
{
scanf("%d%d",&num,&x);
if (num<n)
{
v[f[num]]=2100000000; down(pos[f[num]]);
++tot; v[tot]=abs(x-en[num]); pos[tot]=tot; heap[tot]=tot; up(tot);
++tot; v[tot]=abs(a[num+1]-x); pos[tot]=tot; heap[tot]=tot; f[num]=tot; up(tot);
}
else
{ ++tot; v[tot]=abs(x-en[num]); pos[tot]=tot; heap[tot]=tot; up(tot);}
en[num]=x; mint=v[heap[1]];
t=tpred(roota,x,null);
if (t!=NULL)
minn=min(minn,x-t->val);
t=tsucc(roota,x,null);
if (t!=NULL)
minn=min(minn,t->val-x);
insert(roota,x);
}
if (s[0]=='M')
{
if (s[4]=='S')
printf("%d\n",minn);
if (s[4]=='G')
printf("%d\n",mint);
}
}
}