一道二分水题
读题,他要求满足条件的木棍最长的长度
发现,答案明显满足二分性(最终木根长度越小,可以分出的木棍数就越多)
所以,我们可以直接二分答案,假设当前二分出的答案为x
那么, 对于一个长度为y的木棍来说,它可以分出的最多的长度为x的木棍就是
所以,总共最多可以分出的,长度为x的木棍数就是:
我们将这个值和k比较一下,如果大于k,就说明可以分到x,就往右二分,否则就往左二分,即可
代码:
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+3;
struct splay{
int w,son[2],fa,laz,tot,cnt;
}t[N];
int al,root;
inline bool wy(int x){
return t[t[x].fa].son[1]==x;
}
inline void update(int x){
t[x].tot=(t[t[x].son[0]].tot+t[t[x].son[1]].tot+t[x].cnt);
}
inline void rotate(int x){
int y=t[x].fa,z=t[y].fa,k=wy(x),w=t[x].son[k^1];
t[y].son[k]=w,t[w].fa=y;
t[x].fa=z,t[z].son[wy(y)]=x;
t[x].son[k^1]=y,t[y].fa=x;
update(y),update(x);
}
inline void splay(int x,int gol=0){
while(t[x].fa!=gol){
int y=t[x].fa,z=t[y].fa;
if(z!=gol){
if(wy(x)==wy(y)){
rotate(y);
}else{
rotate(x);
}
}
rotate(x);
}
if(!gol){
root=x;
}
}
inline void insert(int x){
int now=root,fu=0;
while(now){
fu=now,now=t[now].son[x>t[now].w];
}
now=++al;
if(fu){
t[fu].son[x>t[now].w]=al;
}
t[now].w=x,t[now].fa=fu;
t[now].tot=t[now].cnt=1;
splay(now);
}
inline void down(int now){
if(t[now].laz){
swap(t[now].son[0],t[now].son[1]);
t[t[now].son[0]].laz^=1;
t[t[now].son[1]].laz^=1;
t[now].laz=0;
}
}
inline int kth(int k){
int now=root;
while(true){
down(now);
if(t[t[now].son[0]].tot>=k){
now=t[now].son[0];
}else if(t[t[now].son[0]].tot+t[now].cnt<k){
k-=(t[t[now].son[0]].tot+t[now].cnt),now=t[now].son[1];
}else{
return now;
}
}
}
inline void reverse(int l,int r){
int x=kth(l-1),y=kth(r+1);
splay(x),splay(y,x);//这样splay后,y的左子树编号全为l-r
t[t[y].son[0]].laz^=1;
}
int n,m;
inline void print(int now){
down(now);
if(t[now].son[0]){
print(t[now].son[0]);
}
if(now>1&&now<n)
printf("%d ",now-1);
if(t[now].son[1]){
print(t[now].son[1]);
}
}
int main(){
scanf("%d%d",&n,&m);
n+=2;
for(int i=1;i<=n;++i){
insert(i);
}
while(m--){
int l,r;
scanf("%d%d",&l,&r);
++l,++r;
reverse(l,r);
}
print(root);
return 0;
} 
京公网安备 11010502036488号