P5105 不强制在线的动态快速排序 题解
给一发有证明过程的题解:
考虑
结论:
证明:
设
考虑 把每个数写成二进制形式 ,小的在上,大的在下,排在一块。从右至左,以
因为对于
从而
再来看
运用和上文同样的思想,
“对于
k\geq 1 ,f(2^k,2^{k+1}-1) 中有偶数个奇数,这些奇数的异或和中,最高位k 经过了偶数次异或,被消去。”
我们分类讨论:
当
当
综上,
证毕。
进一步地,对于询问
然后用线段树维护,把每一次区间修改下放到若干节点中,每个节点都是满的,解决了不连续的问题。再采用动态开点,解决了定义域过大的问题。
最后附上代码:
#include<bits/stdc++.h>
#define mid ((l+r)>>1)
#define ls (tr[tr[u].l])
#define rs (tr[tr[u].r])
using namespace std;
const int N=3e5+5,INF=1e9;////1e9
typedef long long ll;
struct queryer{
int l,r,type;
}qry[N];
struct treer{
int l,r,min,max;
ll val;
bool vis;
}tr[35*N];
int q,cnt,rt;
ll calc(int p){
if(p%4==0) return 0;
if(p%4==1) return 2*p-1;
if(p%4==2) return 2;
else return 2*p+1;
}
void pushup(int u,int l,int r){
if(!tr[u].l)
return (void)(tr[u].val=rs.val,tr[u].min=rs.min,tr[u].max=rs.max);
if(!tr[u].r)
return (void)(tr[u].val=ls.val,tr[u].min=ls.min,tr[u].max=ls.max);
tr[u].val=ls.val^rs.val^((ll)rs.min*rs.min-(ll)ls.max*ls.max);
tr[u].min=ls.min,tr[u].max=rs.max;
}
void update(int &u,int l,int r,int st,int ed){
if(l>ed || r<st || tr[u].vis) return;
if(!u) u=++cnt;
if(l>=st && r<=ed) return (void)(tr[u]=(treer){0,0,l,r,calc(r)^calc(l),1});
update(tr[u].l,l,mid,st,ed),update(tr[u].r,mid+1,r,st,ed);
pushup(u,l,r);
}
int main(){
scanf("%d",&q);
for(int i=1;i<=q;i++){
scanf("%d",&qry[i].type);
if(qry[i].type==2) continue;
scanf("%d%d",&qry[i].l,&qry[i].r);
}
for(int i=1;i<=q;i++){
if(qry[i].type==2) printf("%lld\n",tr[rt].val);
else update(rt,1,INF,qry[i].l,qry[i].r);
}
return 0;
}
ps:这题差点被你谷管理员CYJian从黑题改成蓝题,原因是太简单