qwq我为了找个指针版的好难啊,调试的时候,指针教我做人(手动再见)。
借鉴了akb的短快涨的代码,写的尽量短了,qwq我觉得把splay写两行也是没谁了。这是BZOJ3224的代码。splay实现treap的功能
//QWsin
//splay 版
#include
#include
#include
#include
#include
using namespace std;
const int maxn=100000+10;
const int INF=1<<30;
inline int read()
{
int ret=0,ok=1;char ch=getchar();
while(ch<'0'||ch>'9') {if(ch=='-')ok=-1;ch=getchar();}
for(;ch>='0'&&ch<='9';ch=getchar()) ret=ret*10+ch-'0';
return ret*ok;
}
struct Node{
int sz,v;
Node *fa,*ch[2];
Node(int v=0):v(v){sz=1;fa=ch[0]=ch[1]=NULL;}
inline int cmp(int x){return x==v?-1:x>v;}
inline void up(){
sz=1;
if(ch[0]!=NULL) sz+=ch[0]->sz;
if(ch[1]!=NULL) sz+=ch[1]->sz;
}
}*pool[maxn*2];
int top=0,n;
inline void init(){for(int i=0;iinline void newnode(Node* &p,int v,Node *fa){
p=pool[top++];*p=Node(v);p->fa=fa;
}
inline void del(Node* &p){pool[--top]=p;p=NULL;}
struct SplayTree{
Node *root;
inline int pd(Node *p){return p->fa->ch[1]==p;}
inline void rotate(Node* p)
{
int c=pd(p)^1;Node *t=p->fa;
t->ch[c^1]=p->ch[c];
if(p->ch[c])p->ch[c]->fa=t;
if((p->fa=t->fa)!=NULL) p->fa->ch[p->fa->ch[1]==t]=p;
t->fa=p;p->ch[c]=t;t->up();p->up();
if(p->fa==NULL) root=p;
}
inline void splay(Node* p,Node *FA)
{
for(;p->fa!=FA;rotate(p))
if(p->fa->fa!=FA) rotate(pd(p)==pd(p->fa)?p->fa:p);
}
void insert(Node* p,int val)
{
if(root==NULL){newnode(root,val,NULL);return ;}
Node *fa=NULL;
while(p!=NULL) fa=p,p=p->ch[val > p->v];
newnode(p,val,fa);fa->ch[val>fa->v]=p;
for(fa=p->fa;fa!=NULL;fa=fa->fa)
fa->up();
splay(p,NULL);
}
inline Node* find(Node *p,int val)
{
while(p!=NULL) {
int tcmp=p->cmp(val);
if(tcmp==-1) return p;
p=p->ch[tcmp];
}
return NULL;
}
Node* MAX(Node* p){
if(p==NULL) return NULL;
while(p->ch[1]!=NULL) p=p->ch[1];
return p;
}
//要求是两颗子树的根,不一定非空
Node* merge(Node* a,Node* b)
{
if(!b) return a;
if(!a) return b;
Node *t=MAX(a);
splay(t,NULL);
t->ch[1]=b;b->fa=t;t->up();
return t;
}
void remove(Node* p,int val)
{
Node* pos=find(root,val);
splay(pos,NULL);
pos=root;del(root);
root=merge(pos->ch[0],pos->ch[1]);
if(root!=NULL)root->fa=NULL;//这里不改会T的
}
inline int rank(Node* p,int val)
{
int ret=1;
while(p!=NULL){
int tcmp=val > p->v,d=p->ch[0]?p->ch[0]->sz:0;
if(tcmp) ret+=d+1; p=p->ch[tcmp];
}
return ret;
}
inline int kth(Node* p,int k)
{
while(p!=NULL){
int d=p->ch[0]?p->ch[0]->sz:0;
if(k==d+1) return p->v;
if(k1) p=p->ch[0];
else k-=d+1,p=p->ch[1];
}
return -1;
}
inline int Pre(Node* p,int val)
{
int ret=-INF;
while(p!=NULL){
int tcmp=val > p->v;
if(tcmp) ret=max(ret,p->v);
p=p->ch[tcmp];
}
return ret;
}
inline int Sub(Node* p,int val)
{
int ret=INF;
while(p!=NULL){
int tcmp=val < p->v;
if(tcmp) ret=min(ret,p->v);
p=p->ch[tcmp^1];
}
return ret;
}
inline void insert(int x){insert(root,x);}
inline void remove(int x){remove(root,x);}
inline int rank(int x){return rank(root,x);}
inline int kth(int x){return kth(root,x);}
inline int Pre(int x){return Pre(root,x);}
inline int Sub(int x){return Sub(root,x);}
}splay;
char s[maxn];int _p;
inline void printf(int x)
{
if(x<0) putchar('-'),x=-x;
if(!x) {putchar('0');return ;}
for(_p=0;x;x/=10) s[++_p]=x%10+'0';
for(int i=_p;i>=1;--i) putchar(s[i]);
putchar('\n');
}
int main()
{
freopen("std.in","r",stdin);
int op,x;cin>>n;init();
while(n--)
{
op=read();x=read();
if(op==1) splay.insert(x);
else if(op==2) splay.remove(x);
else if(op==3) printf(splay.rank(x));
else if(op==4) printf(splay.kth(x));
else if(op==5) printf(splay.Pre(x));
else printf(splay.Sub(x));
}
return 0;
}
渐渐发现splay是一棵,会旋转的线段树!话说节点个数严格n个来着。顿时感觉线段树活了起来(雾)。下面这是codevs线段树练习3的代码。(不过splay好像比线段树跑得慢得多)。
//QWsin
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int maxn=200000+10;
int a[maxn];
struct Node{
int sz,v,add;ll sum;
Node *fa,*ch[2];
Node(){}
inline void up(){
sz=1+ch[0]->sz+ch[1]->sz;
sum=v+ch[0]->sum+ch[1]->sum;
}
inline void push(){
if(!add)return ;
ch[0]->sum+=1ll*ch[0]->sz*add,ch[0]->add+=add,ch[0]->v+=add;
ch[1]->sum+=1ll*ch[1]->sz*add,ch[1]->add+=add,ch[1]->v+=add;
add=0;
}
}*root,*pool[maxn];
Node *null;
struct SplayTree{
int top;
inline void clear(){top=1;}
inline void newnode(Node* &p,int v,Node* fa){
p=pool[top++];p->sz=1;
p->v=p->sum=v;p->add=0;
p->fa=fa;p->ch[0]=p->ch[1]=null;
}
//如果p是p->fa的右儿子返回1
inline int pd(Node* p){return p->fa->ch[1]==p;}
inline void rotate(Node* p)
{
int c=pd(p)^1;Node *f=p->fa;
f->ch[c^1]=p->ch[c];p->ch[c]->fa=f;
if((p->fa=f->fa)!=null) p->fa->ch[p->fa->ch[1]==f]=p;
f->fa=p;p->ch[c]=f;f->up();p->up();
if(p->fa==null) root=p;//记得换根
}
inline void splay(Node* p,Node *FA)
{
for(p->push();p->fa!=FA;rotate(p))
if(p->fa->fa!=FA) rotate(pd(p)==pd(p->fa)?p:p->fa);
}
inline void find_rot(int k,Node* FA)//找到并旋转为FA的儿子
{
Node* p=root;p->push();
while(p!=null)
{
if(k == p->ch[0]->sz +1) break;
if(k<=p->ch[0]->sz) p=p->ch[0];
else k-=p->ch[0]->sz+1,p=p->ch[1];
p->push();
}
if(p==null) return ;
splay(p,FA);
}
//------以上为常用函数
#define mid ((l+r)>>1)
inline void build(Node* &p,int l,int r,Node *fa)
{
if(rreturn ;
newnode(p,a[mid],fa);
build(p->ch[0],l,mid-1,p);
build(p->ch[1],mid+1,r,p);p->up();
}
#undef mid
inline void init(){
for(int i=0;inew Node();
null=new Node();
null->v=null->sum=null->sz=0;null->add=0;
null->ch[0]=null->ch[1]=null->fa=NULL;
int n;cin>>n;
for(int i=1;i<=n;++i) scanf("%d",a+i);
newnode(root,0,null);//为了防止RE需要建立虚节点
newnode(root->ch[1],0,root);root->sz=2;
build(root->ch[1]->ch[0],1,n,root->ch[1]);
root->ch[1]->up();root->up();
}
inline void updata(int l,int r,int val)
{
find_rot(l,null);find_rot(r+2,root);//因为有两个虚点所以rank要+1
Node *t=root->ch[1]->ch[0];
t->v+=val;t->add+=val;t->sum+=1ll*t->sz*val;
}
inline ll query(int l,int r)
{
find_rot(l,null);find_rot(r+2,root);
return root->ch[1]->ch[0]->sum;
}
//根据题目性质 上面为类似线段树的东西
}spt;
int main()
{
spt.init();
int Q,op,a,b,c;cin>>Q;
while(Q--)
{
scanf("%d",&op);
if(op==1) {
scanf("%d%d%d",&a,&b,&c);
spt.updata(a,b,c);
}
else{
scanf("%d%d",&a,&b);
printf("%lld\n",spt.query(a,b));
}
}
return 0;
}
所以splay真的很强大。要是快一点的话简直无敌了。
初衷是为了学习lct才复习的splay,下面是lct的模板,BZOJ2002弹飞绵羊,注意splay和rotate函数和写裸的splay的差别比较大,主要分清楚辅助树的根和原来树的根这两个概念,,另外zzq学长说版子一定要找对,他第一份lct调了三天,当时他好像把splay旋断了,旋出环了qwq,幸好我调了两个小时就过了qwq主要还是splay没什么问题了,借鉴了一下这位的代码。代码戳这里。因为指针的lct实在太难找了qwq,找了一份模拟链表的。
//QWsin
#include
#include
#include
#include
#include
using namespace std;
const int maxn=200000+10;
inline int read()
{
int ret=0;char ch=getchar();
while(ch<'0'||ch>'9') ch=getchar();
for(;ch>='0'&&ch<='9';ch=getchar()) ret=ret*10+ch-'0';
return ret;
}
char s[20];int _p;
inline void output(int x)
{
if(!x){putchar('0');return ;}
for(_p=0;x;x/=10) s[++_p]=x%10+'0';
for(int i=_p;i>=1;--i) putchar(s[i]);
putchar('\n');
}
struct Node {
int sz,rev;
Node *fa,*ch[2];
Node() {sz=1;rev=0;fa=ch[0]=ch[1]=NULL;}
inline void up() {
sz=1;
if(ch[0]) sz+=ch[0]->sz;
if(ch[1]) sz+=ch[1]->sz;
}
inline void push() {
if(!rev) return ;
swap(ch[0],ch[1]);rev=0;
if(ch[0])ch[0]->rev^=1;
if(ch[1])ch[1]->rev^=1;
}
}*pool[maxn*2],*tmp[maxn];
int top=0;
inline void init_pool() {
for(int i=0; inew Node();
}
inline void newnode(Node* &p,Node *fa) {p=pool[top++];*p=Node();p->fa=fa;}
inline void del(Node* &p) {pool[--top]=p;p=NULL;}
int to[maxn],n;
struct LinkCutTree {
Node *node[maxn];
inline void init(int n) {for(int i=1; i<=n; ++i) newnode(node[i],NULL);}
inline int is_root(Node* p) {
return !(p->fa)||(p->fa->ch[0]!=p&&p->fa->ch[1]!=p);
}
inline int pd(Node* p) {return p->fa->ch[1]==p;}
inline void rotate(Node* p) {
int c=pd(p)^1;Node *t=p->fa;
t->ch[c^1]=p->ch[c];
if(p->ch[c]) p->ch[c]->fa=t;
p->fa=t->fa;
if(!is_root(t)) p->fa->ch[pd(t)]=p;
t->fa=p;p->ch[c]=t;t->up();p->up();
}
inline void splay(Node* p) {
int pos=0;
for(Node *t=p;; t=t->fa) {
tmp[++pos]=t;
if(is_root(t)) break;
}
for(; pos>=1; --pos) tmp[pos]->push();
for(; !is_root(p); rotate(p))
if(!is_root(p->fa)) rotate(pd(p)==pd(p->fa)?p->fa:p);
p->up();
}
inline void access(Node* p) {
for(Node* pre=NULL; p; pre=p,p=p->fa)
splay(p),p->ch[1]=pre,p->up();
}
inline void make_root(Node* p) {access(p);splay(p);p->rev^=1;}
inline void cut(Node *x,Node *y) {
make_root(x);access(y);splay(y);
x->fa=y->ch[0]=NULL;y->up();
}
//因为link之后x不是y的splay上的儿子所以y不up
inline void link(Node *x,Node *y) {make_root(x);x->fa=y;}
inline void link(int x,int y) {node[x]->fa=node[y];}
inline void op1(int x) {
make_root(node[n+1]);
access(node[x]);
splay(node[x]);
output(node[x]->ch[0]->sz);
}
inline void op2(int x,int y) {
cut(node[x],node[min(x+to[x],n+1)]);
to[x]=y;
link(node[x],node[min(x+to[x],n+1)]);
}
} lct;
int main() {
cin>>n;
init_pool();
lct.init(n+1);
for(int i=1; i<=n; ++i) {
to[i]=read();
lct.link(i,min(i+to[i],n+1));
}
int Q,op,x,y;
cin>>Q;
while(Q--) {
scanf("%d",&op);
if(op==1) lct.op1(read()+1);
else {
x=read();y=read();
lct.op2(++x,y);
}
}
return 0;
}