生活随笔
收集整理的這篇文章主要介紹了
[luogu2042] [NOI2005]维护数列
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
前言
寫寫比較麻煩的這題
題目相關
題目大意
寫一個大數據結構
數據范圍
20000
題目鏈接
前置
先過模板題,比如會個非旋treap,寫一下,通過[luogu3369][模板]普通平衡樹
possible version
#include<cstdio>
#include<cctype>
#include<cmath>
#include<algorithm>
#include<cstdlib>
#include<ctime>
#define rg register
namespace fast_IO
{const int IN_LEN
=1000000,OUT_LEN
=1000000;char ibuf
[IN_LEN
],obuf
[OUT_LEN
],*ih
=ibuf
+IN_LEN
,*oh
=obuf
,*lastin
=ibuf
+IN_LEN
,*lastout
=obuf
+OUT_LEN
-1;inline char getchar_(){return (ih
==lastin
)&&(lastin
=(ih
=ibuf
)+fread(ibuf
,1,IN_LEN
,stdin),ih
==lastin
)?EOF:*ih
++;}inline void putchar_(const char x
){if(oh
==lastout
)fwrite(obuf
,1,oh
-obuf
,stdout),oh
=obuf
;*oh
++=x
;}inline void flush(){fwrite(obuf
,1,oh
-obuf
,stdout);}
}
using namespace fast_IO
;
#define getchar() getchar_()
#define putchar(x) putchar_((x))
typedef long long ll
;
template
<typename T
>inline T
min(const T x
,const T y
){return x
<y
?x
:y
;}
template
<typename T
>inline T
max(const T x
,const T y
){return x
>y
?x
:y
;}
template
<typename T
>inline T
abs(const T x
){return x
>0?x
:-x
;}
template
<typename T
>inline T
gcd(const T a
,const T b
){if(!b
)return a
;return gcd(b
,a
%b
);}
template
<typename T
>inline void swap(T
&a
,T
&b
){const T c
=a
;a
=b
;b
=c
;}
template
<typename T
>inline void read(T
&x
)
{char cu
=getchar();bool fla
=0;x
=0;while(!isdigit(cu
)){if(cu
=='-')fla
=1;cu
=getchar();}while(isdigit(cu
))x
=x
*10+cu
-'0',cu
=getchar();if(fla
)x
=-x
;
}
template
<typename T
>inline void printe(const T x
)
{if(x
>=10)printe(x
/10);putchar(x
%10+'0');
}
template
<typename T
>inline void print(const T x
)
{if(x
<0)putchar('-'),printe(-x
);else printe(x
);
}
const int maxn
=500001;
struct Point
{int x
,key
,lson
,rson
,size
;
}Q
[maxn
];int usd
,root
;
int newnode(const int v
)
{usd
++;Q
[usd
]=(Point
){v
,rand(),0,0,1};return usd
;
}
void update(const int x
)
{Q
[x
].size
=Q
[Q
[x
].lson
].size
+Q
[Q
[x
].rson
].size
+1;
}
std
::pair
<int,int> split(const int x
,const int v
)
{std
::pair
<int,int>res(0,0);if(!x
)return res
;if(Q
[x
].x
<=v
){res
=split(Q
[x
].rson
,v
);Q
[x
].rson
=res
.first
;res
.first
=x
;}else{res
=split(Q
[x
].lson
,v
);Q
[x
].lson
=res
.second
;res
.second
=x
;}update(x
);return res
;
}
int merge(int x
,int y
)
{if(!x
)return y
;if(!y
)return x
;if(Q
[x
].key
<Q
[y
].key
){Q
[x
].rson
=merge(Q
[x
].rson
,y
);update(x
);return x
;}else{Q
[y
].lson
=merge(x
,Q
[y
].lson
);update(y
);return y
;}
}
void insert(const int x
)
{std
::pair
<int,int> R
=split(root
,x
);root
=merge(merge(R
.first
,newnode(x
)),R
.second
);
}
void del(const int x
)
{std
::pair
<int,int> R
=split(root
,x
),T
=split(R
.first
,x
-1);if(T
.second
==0)return;root
=merge(merge(T
.first
,merge(Q
[T
.second
].lson
,Q
[T
.second
].rson
)),R
.second
);
}
int rerank(int v
)
{int x
=root
,ans
=0;while(x
){if(Q
[x
].x
<v
)ans
+=Q
[Q
[x
].lson
].size
+1,x
=Q
[x
].rson
;else x
=Q
[x
].lson
;}return ans
+1;
}
int atrank(int rk
)
{int x
=root
;while(1){const int all
=Q
[Q
[x
].lson
].size
+1;if(all
==rk
)return Q
[x
].x
;if(all
<rk
)x
=Q
[x
].rson
,rk
-=all
;else x
=Q
[x
].lson
;}
}
int prec(int v
)
{int x
=root
,ans
=0;while(x
){if(Q
[x
].x
<v
)ans
=Q
[x
].x
,x
=Q
[x
].rson
;else x
=Q
[x
].lson
;}return ans
;
}
int succ(int v
)
{int x
=root
,ans
=0;while(x
){if(Q
[x
].x
>v
)ans
=Q
[x
].x
,x
=Q
[x
].lson
;else x
=Q
[x
].rson
;}return ans
;
}
int n
;
int main()
{read(n
),srand(time(0));for(rg
int i
=1;i
<=n
;i
++){int opt
,x
;read(opt
),read(x
);if(opt
==1)insert(x
);else if(opt
==2)del(x
);else if(opt
==3)print(rerank(x
)),putchar('\n');else if(opt
==4)print(atrank(x
)),putchar('\n');else if(opt
==5)print(prec(x
)),putchar('\n');else print(succ(x
)),putchar('\n');}return flush(),0;
}
題解
我們發現這里是要維護序列,那么我們需要把split魔改一下,改成“把第1-x個數放到左子樹,其余放到右子樹”
接下來我們考慮操作
首先我們發現初始在treap中的那些數等價于一次insert操作,所以在此不討論
接下來,講述每個操作的做法
版本1(代碼已刪除):
我的代碼中把log變成了sort的,rand值直接從上到下填即可
版本2(本文代碼):
構造笛卡爾樹,復雜度變成次數log加上數量了,減小常數
- 刪除
直接旋出來那棵樹,不過值得注意的是,需要對節點進行回收,否則空間復雜度受不了 - 修改
打個子樹修改標記即可 - 翻轉
打個子樹修改標記即可 - 求和
記錄子樹權值和即可 - 求和最大的子列
記錄子列中最大的子段,最大前綴,最大后綴
值得注意的是,由于題目所述的區間長度必須大于0,所以要注意負權點的處理
這題看起來非常的簡單,其實在具體實現過程中要注意各個標記之間的影響,需要實現好
另外,注意翻轉標記下傳是翻轉狀態,不然很容易調不出來
code
#include<cstdio>
#include<cctype>
#include<cmath>
#include<algorithm>
#include<cstdlib>
#include<ctime>
#define rg register
namespace fast_IO
{const int IN_LEN
=1000000,OUT_LEN
=1000000;char ibuf
[IN_LEN
],obuf
[OUT_LEN
],*ih
=ibuf
+IN_LEN
,*oh
=obuf
,*lastin
=ibuf
+IN_LEN
,*lastout
=obuf
+OUT_LEN
-1;inline char getchar_(){return (ih
==lastin
)&&(lastin
=(ih
=ibuf
)+fread(ibuf
,1,IN_LEN
,stdin),ih
==lastin
)?EOF:*ih
++;}inline void putchar_(const char x
){if(oh
==lastout
)fwrite(obuf
,1,oh
-obuf
,stdout),oh
=obuf
;*oh
++=x
;}inline void flush(){fwrite(obuf
,1,oh
-obuf
,stdout);}
}
using namespace fast_IO
;
#define getchar() getchar_()
#define putchar(x) putchar_((x))
typedef long long ll
;
template
<typename T
>inline T
min(const T x
,const T y
){return x
<y
?x
:y
;}
template
<typename T
>inline T
max(const T x
,const T y
){return x
>y
?x
:y
;}
template
<typename T
> inline void mind(T
&a
,const T b
){a
=a
<b
?a
:b
;}
template
<typename T
> inline void maxd(T
&a
,const T b
){a
=a
>b
?a
:b
;}
template
<typename T
>inline T
abs(const T x
){return x
>0?x
:-x
;}
template
<typename T
>inline T
gcd(const T a
,const T b
){if(!b
)return a
;return gcd(b
,a
%b
);}
template
<typename T
>inline void swap(T
&a
,T
&b
){const T c
=a
;a
=b
;b
=c
;}
template
<typename T
>inline void read(T
&x
)
{char cu
=getchar();bool fla
=0;x
=0;while(!isdigit(cu
)){if(cu
=='-')fla
=1;cu
=getchar();}while(isdigit(cu
))x
=x
*10+cu
-'0',cu
=getchar();if(fla
)x
=-x
;
}
template
<typename T
>inline void printe(const T x
)
{if(x
>=10)printe(x
/10);putchar(x
%10+'0');
}
template
<typename T
>inline void print(const T x
)
{if(x
<0)putchar('-'),printe(-x
);else printe(x
);
}
const int maxn
=500001;
struct Point
{int x
,key
,lson
,rson
,size
;int zuoda
,youda
,zhong
,he
;bool flag
;int change
;
}Q
[maxn
];int root
;
void blbl(const int x
)
{if(!x
)return;printf("%d\n",Q
[x
].x
);blbl(Q
[x
].lson
);blbl(Q
[x
].rson
);
}
int rubbish
[maxn
],top
;
int newnode(const int R
)
{int usd
=rubbish
[top
--];Q
[usd
]=(Point
){0,R
,0,0,1,0,0,0,0,0,-1001};return usd
;
}
void change(Point
&hos
,const int x
)
{hos
.x
=x
;maxd(hos
.zuoda
,x
),maxd(hos
.youda
,x
);hos
.zhong
=x
;hos
.he
+=x
;
}
void deal_flag(Point
&hos
)
{swap(hos
.lson
,hos
.rson
);swap(hos
.zuoda
,hos
.youda
);hos
.flag
^=1;
}
void deal_change(Point
&hos
,const int x
)
{hos
.x
=x
;if(x
>0)hos
.zuoda
=hos
.youda
=hos
.zhong
=hos
.he
=hos
.size
*x
;else hos
.zuoda
=hos
.youda
=0,hos
.zhong
=x
,hos
.he
=hos
.size
*x
;hos
.change
=x
;
}
void down(Point
&hos
)
{int w
=hos
.lson
;if(w
){if(hos
.flag
)deal_flag(Q
[w
]);if(hos
.change
!=-1001)deal_change(Q
[w
],hos
.change
);}w
=hos
.rson
;if(w
){if(hos
.flag
)deal_flag(Q
[w
]);if(hos
.change
!=-1001)deal_change(Q
[w
],hos
.change
);}hos
.flag
=0,hos
.change
=-1001;
}
void update(Point
&hos
)
{Point
&L
=Q
[hos
.lson
],&R
=Q
[hos
.rson
];hos
.size
=L
.size
+R
.size
+1;hos
.he
=L
.he
+R
.he
+hos
.x
;hos
.zuoda
=max(L
.zuoda
,L
.he
+hos
.x
+R
.zuoda
);hos
.youda
=max(R
.youda
,R
.he
+hos
.x
+L
.youda
);hos
.zhong
=max(max(L
.zhong
,R
.zhong
),L
.youda
+hos
.x
+R
.zuoda
);
}
std
::pair
<int,int> split(const int x
,const int kth
)
{std
::pair
<int,int>res(0,0);if(!x
)return res
;down(Q
[x
]);if(Q
[Q
[x
].lson
].size
+1==kth
){res
.first
=x
,res
.second
=Q
[x
].rson
;Q
[x
].rson
=0;}else if(Q
[Q
[x
].lson
].size
+1<kth
){res
=split(Q
[x
].rson
,kth
-(Q
[Q
[x
].lson
].size
+1));Q
[x
].rson
=res
.first
;res
.first
=x
;}else{res
=split(Q
[x
].lson
,kth
);Q
[x
].lson
=res
.second
;res
.second
=x
;}update(Q
[x
]);return res
;
}
int merge(int x
,int y
)
{if(!x
)return y
;if(!y
)return x
;down(Q
[x
]),down(Q
[y
]);if(Q
[x
].key
<Q
[y
].key
){Q
[x
].rson
=merge(Q
[x
].rson
,y
);update(Q
[x
]);return x
;}else{Q
[y
].lson
=merge(x
,Q
[y
].lson
);update(Q
[y
]);return y
;}
}
int m
,P
[maxn
],Ptop
;
char opt
[11];int opttop
;
int STA
[maxn
],Stop
,ID
[maxn
];
int maker()
{int rando
=rand();STA
[Stop
=1]=newnode(rando
),ID
[Stop
]=P
[1];for(rg
int i
=2;i
<=Ptop
;i
++){int ME
=newnode(rando
);rando
=rand();bool fla
=0;while(Stop
>1&&rando
<Q
[STA
[Stop
]].key
)Q
[STA
[Stop
-1]].rson
=STA
[Stop
],change(Q
[STA
[Stop
]],ID
[Stop
]),update(Q
[STA
[Stop
]]),Stop
--,fla
=1;if(rando
<Q
[STA
[Stop
]].key
){change(Q
[STA
[Stop
]],ID
[Stop
]),update(Q
[STA
[Stop
]]);Q
[ME
].lson
=STA
[Stop
];STA
[Stop
]=ME
,ID
[Stop
]=P
[i
];}else{if(fla
){Q
[STA
[Stop
]].rson
=0;Q
[ME
].lson
=STA
[Stop
+1];}STA
[++Stop
]=ME
,ID
[Stop
]=P
[i
];}}while(Stop
>1)Q
[STA
[Stop
-1]].rson
=STA
[Stop
],change(Q
[STA
[Stop
]],ID
[Stop
]),update(Q
[STA
[Stop
]]),Stop
--;change(Q
[STA
[Stop
]],ID
[Stop
]),update(Q
[STA
[Stop
]]);return STA
[1];
}
void insert(const int x
)
{std
::pair
<int,int>T
=split(root
,x
);root
=merge(merge(T
.first
,maker()),T
.second
);
}
void rerubbish(const int x
)
{if(!x
)return;rubbish
[++top
]=x
;rerubbish(Q
[x
].lson
),rerubbish(Q
[x
].rson
);
}
void del(const int x
)
{std
::pair
<int,int>T
=split(root
,x
),S
=split(T
.second
,Ptop
);rerubbish(S
.first
);root
=merge(T
.first
,S
.second
);
}
int samv
;
void sam(const int x
)
{std
::pair
<int,int>T
=split(root
,x
),S
=split(T
.second
,Ptop
);deal_change(Q
[S
.first
],samv
);root
=merge(merge(T
.first
,S
.first
),S
.second
);
}
void reverse(const int x
)
{std
::pair
<int,int>T
=split(root
,x
),S
=split(T
.second
,Ptop
);deal_flag(Q
[S
.first
]);root
=merge(merge(T
.first
,S
.first
),S
.second
);
}
int sum(const int x
)
{std
::pair
<int,int>T
=split(root
,x
),S
=split(T
.second
,Ptop
);int res
=Q
[S
.first
].he
;root
=merge(merge(T
.first
,S
.first
),S
.second
);return res
;
}
int bigv(const int x
)
{return Q
[root
].zhong
;
}
int main()
{Q
[0].zhong
=-(0x7f7f7f7f);for(rg
int i
=1;i
<=500000;i
++)rubbish
[++top
]=i
;read(Ptop
),read(m
),srand(time(0));for(rg
int i
=1;i
<=Ptop
;i
++)read(P
[i
]);insert(0);for(rg
int i
=1;i
<=m
;i
++){int x
;opt
[opttop
=1]=getchar();while(opt
[1]<'A'||opt
[1]>'Z')opt
[1]=getchar();while(opt
[opttop
]!=' '&&opt
[opttop
]!='\n'&&opt
[opttop
]!=EOF)opt
[++opttop
]=getchar();if(opt
[1]=='I'){read(x
),read(Ptop
);for(rg
int i
=1;i
<=Ptop
;i
++)read(P
[i
]);insert(x
);}else if(opt
[1]=='D'){read(x
),read(Ptop
);x
--;del(x
);} else if(opt
[3]=='K'){read(x
),read(Ptop
),read(samv
);x
--;sam(x
);}else if(opt
[1]=='R'){read(x
),read(Ptop
);x
--;reverse(x
);}else if(opt
[1]=='G'){read(x
),read(Ptop
);x
--;print(sum(x
)),putchar('\n');}else print(bigv(root
)),putchar('\n');}return flush(),0;
}
總結
一道較為繁瑣的數據結構,調了有一會兒,馬上就要csp了,還得加強代碼熟練度
總結
以上是生活随笔為你收集整理的[luogu2042] [NOI2005]维护数列的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。