[Luogu5105]不强制在线的动态快速排序

首先集合去重不影响答案,然后打表易得连续自然数平方差异或前缀和的规律,于是问题就变为在线维护区间求并同时更新答案,set记录所有区间,每次暴力插入删除即可。由于每个区间至多只会插入删除一次,故均摊复杂度$O(n\log n)$

 1 #include<set>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
 5 typedef long long ll;
 6 using namespace std;
 7 
 8 const int N=300010;
 9 int Q,op,l,r;
10 ll ans;
11 struct P{ int l,r; };
12 bool operator <(const P &a,const P &b){ return a.l<b.l; }
13 set<P>S;
14 
15 ll D(int n){
16     n=(n+1)/2;
17     if (n%4==1) return 2*n-1;
18     if (n%4==2) return 2;
19     if (n%4==3) return 2*n+1;
20     return 0;
21 }
22 
23 ll calc(int l,int r){ if (l==r) return 0; else return D(r*2-1)^D(l*2-1); }
24 
25 ll get(set<P>::iterator it){
26     int l=it->l,r=it->r,u=-1,v=-1; ll res=calc(l,r);
27     it++; if (it!=S.end()) res^=1ll*((it->l)+r)*((it->l)-r),u=it->l;
28     it--; if (it!=S.begin()) it--,res^=1ll*(l+(it->r))*(l-(it->r)),v=it->r;
29     if (~u && ~v) res^=1ll*(u+v)*(u-v);
30     return res;
31 }
32 
33 void work(int l,int r){
34     if (S.empty()) { ans=calc(l,r); S.insert((P){l,r}); return; }
35     set<P>::iterator it=S.lower_bound((P){l,r});
36     while (it!=S.end() && it->l<=r)
37         l=min(l,it->l),r=max(r,it->r),ans^=get(it),S.erase(it),it=S.lower_bound((P){l,r});
38     if (it!=S.begin()){
39         it--;
40         while (it->r>=l){
41             l=min(l,it->l); r=max(r,it->r); ans^=get(it); S.erase(it);
42             it=S.lower_bound((P){l,r});
43             if (it==S.begin()) break; else it--;
44         }
45     }
46     it=S.insert((P){l,r}).first; ans^=get(it);
47     //for (it=S.begin(); it!=S.end(); it++) printf("%d %d\n",it->l,it->r); puts("");
48 }
49 
50 int main(){
51     for (scanf("%d",&Q); Q--; ){
52         scanf("%d",&op);
53         if (op==1) scanf("%d%d",&l,&r),work(l,r); else printf("%lld\n",ans);
54     }
55     return 0;
56 }

 

posted @ 2019-01-05 19:06  HocRiser  阅读(163)  评论(0编辑  收藏  举报