洛谷 P2824 [HEOI2016/TJOI2016]排序 (线段树合并)
(另外:题解中有一种思路很高妙而且看上去可以适用一些其他情况的离线方法)
线段树合并&复杂度的简单说明:https://blog.csdn.net/zawedx/article/details/51818475
调用一次合并函数的时间是常数,
而合并函数每调用一次就会删掉一个点,
所以合并的总代价为删掉的点数和,
或者理解为:
所以好像要合并就不能可持久化?(指保留每一个版本,在合并后仍旧保留合并前的版本)(不确定)
(部分的可持久化应该是可以的,就是在每次合并后保留合并前的版本,但合并前的版本不能再次拿去合并了)
(就是在merge里改一下,如果两个节点同时不为空则新建一个节点而不是直接把其中一个节点当成新节点)
(原因是,这样子相当于每调用一次merge函数从最多删掉一个点变成最多增加一个点;而显然调用merge函数的次数一定是对的,那么增加的空间复杂度也是对的)
此题就是个线段树合并裸题了,额外用一个set维护序列中某一段区间对应的权值线段树的根节点。区间排序就找出set中所有与询问区间相交的区间,将相交部分分裂出来(对应线段树的部分也要分裂出来,可能是前k大或后k大或整一段),然后将剩余部分插回set,最后将所有分出来的相交部分并起来,就得到询问区间排好序的权值线段树。复杂度是n*log
错误记录:空间开成O(n),
没删调试信息的代码:
1 #include<cstdio> 2 #include<algorithm> 3 #include<set> 4 using namespace std; 5 int n,m; 6 namespace SegT 7 { 8 const int N=600000; 9 int lc[N],rc[N],dat[N]; 10 int st[N+10];int top; 11 void init() {for(int i=N-1;i>=1;i--)st[++top]=i;} 12 int getnode() {int t=st[top--];lc[t]=rc[t]=dat[t]=0;return t;} 13 void delnode(int x) {st[++top]=x;} 14 #define mid (l+((r-l)>>1)) 15 int L,x; 16 void _addx(int l,int r,int &num) 17 { 18 if(!num) num=getnode(); 19 if(l==r) {dat[num]+=x;return;} 20 if(L<=mid) _addx(l,mid,lc[num]); 21 else _addx(mid+1,r,rc[num]); 22 dat[num]=dat[lc[num]]+dat[rc[num]]; 23 } 24 void addx(int pos,int &num) {L=pos;x=1;_addx(1,n,num);} 25 void split(int l,int r,int &num,int &x,int k) 26 //当前区间为[l,r],将num中的前k小拆出来,放到x中 27 { 28 //assert(dat[num]>=k&&k>0); 29 if(!k) return; 30 if(!x) x=getnode(); 31 if(l==r) {dat[num]-=k;dat[x]+=k;return;} 32 int t=dat[lc[num]]; 33 if(t>k) split(l,mid,lc[num],lc[x],k); 34 else lc[x]=lc[num],lc[num]=0; 35 if(t<k) split(mid+1,r,rc[num],rc[x],k-t); 36 dat[num]=dat[lc[num]]+dat[rc[num]]; 37 dat[x]=dat[lc[x]]+dat[rc[x]]; 38 } 39 int merge(/*int l,int r,*/int num,int x) 40 //将x和num并起来 41 { 42 if(!x||!num) return x+num; 43 //if(l==r) {dat[num]+=dat[x];delnode(x);return;} 44 lc[num]=merge(lc[num],lc[x]); 45 rc[num]=merge(rc[num],rc[x]); 46 dat[num]+=dat[x]; 47 delnode(x); 48 return num; 49 // if(!lc[num]||!lc[x]) lc[num]=lc[num]+lc[x]; 50 // else merge(l,mid,lc[num],lc[x]); 51 // if(!rc[num]||!rc[x]) rc[num]=rc[num]+rc[x]; 52 // else merge(mid+1,r,rc[num],rc[x]); 53 // dat[num]=dat[lc[num]]+dat[rc[num]]; 54 // delnode(x); 55 } 56 int _query_kth(int l,int r,int k,int num) 57 { 58 if(l==r) return l; 59 if(dat[lc[num]]>=k) return _query_kth(l,mid,k,lc[num]); 60 else return _query_kth(mid+1,r,k-dat[lc[num]],rc[num]); 61 } 62 int query_kth(int k,int num) 63 { 64 return _query_kth(1,n,k,num); 65 } 66 #undef mid 67 } 68 struct Dat 69 { 70 int r,l,nd,type;//type=0升序,type=1降序 71 }; 72 bool operator<(const Dat &a,const Dat &b) 73 { 74 return a.r<b.r||(a.r==b.r&&a.l<b.l); 75 } 76 set<Dat> s; 77 int split_node(int l,int r) 78 { 79 int ansn=0,tn;Dat t; 80 auto it=s.lower_bound((Dat){l,0,0,0}); 81 if(it->l!=l) 82 { 83 t=*it;s.erase(it);tn=0; 84 if(t.type==0) 85 { 86 SegT::split(1,n,t.nd,tn,l-t.l); 87 s.insert((Dat){l-1,t.l,tn,0}); 88 //ansn=SegT::merge(ansn,t.nd); 89 s.insert((Dat){t.r,l,t.nd,0}); 90 } 91 else 92 { 93 SegT::split(1,n,t.nd,tn,t.r-l+1); 94 s.insert((Dat){l-1,t.l,t.nd,1}); 95 //ansn=SegT::merge(ansn,tn); 96 s.insert((Dat){t.r,l,tn,1}); 97 } 98 } 99 it=s.lower_bound((Dat){r,0,0,0}); 100 if(it->r!=r) 101 { 102 t=*it;s.erase(it);tn=0; 103 if(t.type==0) 104 { 105 SegT::split(1,n,t.nd,tn,r-t.l+1); 106 s.insert((Dat){t.r,r+1,t.nd,0}); 107 //ansn=SegT::merge(ansn,tn); 108 s.insert((Dat){r,t.l,tn,0}); 109 } 110 else 111 { 112 SegT::split(1,n,t.nd,tn,t.r-r); 113 s.insert((Dat){t.r,r+1,tn,1}); 114 //ansn=SegT::merge(ansn,t.nd); 115 s.insert((Dat){r,t.l,t.nd,1}); 116 } 117 } 118 while(1) 119 { 120 it=s.lower_bound((Dat){l,0,0,0}); 121 if(it==s.end()||it->l>r) break; 122 t=*it;s.erase(it); 123 ansn=SegT::merge(ansn,t.nd); 124 } 125 return ansn; 126 } 127 //void out() 128 //{ 129 // for(auto i : s) 130 // { 131 // printf("a%d %d %d %d\n",i.r,i.l,i.nd,i.type); 132 // } 133 //} 134 int main() 135 { 136 SegT::init(); 137 int t,t2,i,idx,l,r,q; 138 scanf("%d%d",&n,&m); 139 for(i=1;i<=n;i++) 140 { 141 scanf("%d",&t); 142 t2=SegT::getnode(); 143 SegT::addx(t,t2); 144 s.insert((Dat){i,i,t2,0}); 145 } 146 while(m--) 147 { 148 scanf("%d%d%d",&idx,&l,&r); 149 t=split_node(l,r); 150 s.insert((Dat){r,l,t,idx}); 151 } 152 scanf("%d",&q); 153 t=split_node(q,q); 154 printf("%d",SegT::query_kth(1,t)); 155 return 0; 156 }
删了一些奇怪调试代码之后的代码:
1 #pragma GCC optimize("Ofast") 2 #pragma GCC optimize("inline","fast-math","unroll-loops","no-stack-protector") 3 #pragma GCC diagnostic error "-fwhole-program" 4 #pragma GCC diagnostic error "-fcse-skip-blocks" 5 #pragma GCC diagnostic error "-funsafe-loop-optimizations" 6 #pragma GCC diagnostic error "-std=c++14" 7 #include<cstdio> 8 #include<algorithm> 9 #include<set> 10 using namespace std; 11 int n,m; 12 namespace SegT 13 { 14 const int N=600000; 15 int lc[N],rc[N],dat[N]; 16 int st[N+10];int top; 17 void init() {for(int i=N-1;i>=1;i--)st[++top]=i;} 18 int getnode() {int t=st[top--];lc[t]=rc[t]=dat[t]=0;return t;} 19 void delnode(int x) {st[++top]=x;} 20 #define mid (l+((r-l)>>1)) 21 int L,x; 22 void _addx(int l,int r,int &num) 23 { 24 if(!num) num=getnode(); 25 if(l==r) {dat[num]+=x;return;} 26 if(L<=mid) _addx(l,mid,lc[num]); 27 else _addx(mid+1,r,rc[num]); 28 dat[num]=dat[lc[num]]+dat[rc[num]]; 29 } 30 void addx(int pos,int &num) {L=pos;x=1;_addx(1,n,num);} 31 void split(int l,int r,int &num,int &x,int k) 32 //当前区间为[l,r],将num中的前k小拆出来,放到x中 33 { 34 if(!k) return; 35 if(!x) x=getnode(); 36 if(l==r) {dat[num]-=k;dat[x]+=k;return;} 37 int t=dat[lc[num]]; 38 if(t>k) split(l,mid,lc[num],lc[x],k); 39 else lc[x]=lc[num],lc[num]=0; 40 if(t<k) split(mid+1,r,rc[num],rc[x],k-t); 41 dat[num]=dat[lc[num]]+dat[rc[num]]; 42 dat[x]=dat[lc[x]]+dat[rc[x]]; 43 } 44 int merge(int num,int x) 45 //将x和num并起来 46 { 47 if(!x||!num) return x+num; 48 //if(l==r) {dat[num]+=dat[x];delnode(x);return;}//不用判的 49 lc[num]=merge(lc[num],lc[x]); 50 rc[num]=merge(rc[num],rc[x]); 51 dat[num]+=dat[x]; 52 delnode(x); 53 return num; 54 } 55 int _query_kth(int l,int r,int k,int num) 56 { 57 if(l==r) return l; 58 if(dat[lc[num]]>=k) return _query_kth(l,mid,k,lc[num]); 59 else return _query_kth(mid+1,r,k-dat[lc[num]],rc[num]); 60 } 61 int query_kth(int k,int num) 62 { 63 return _query_kth(1,n,k,num); 64 } 65 #undef mid 66 } 67 struct Dat 68 { 69 int r,l,nd,type;//type=0升序,type=1降序 70 }; 71 bool operator<(const Dat &a,const Dat &b) 72 { 73 return a.r<b.r||(a.r==b.r&&a.l<b.l); 74 } 75 set<Dat> s; 76 int split_node(int l,int r) 77 { 78 int ansn=0,tn;Dat t; 79 auto it=s.lower_bound((Dat){l,0,0,0}); 80 if(it->l!=l) 81 { 82 t=*it;s.erase(it);tn=0; 83 if(t.type==0) 84 { 85 SegT::split(1,n,t.nd,tn,l-t.l); 86 s.insert((Dat){l-1,t.l,tn,0}); 87 s.insert((Dat){t.r,l,t.nd,0}); 88 } 89 else 90 { 91 SegT::split(1,n,t.nd,tn,t.r-l+1); 92 s.insert((Dat){l-1,t.l,t.nd,1}); 93 s.insert((Dat){t.r,l,tn,1}); 94 } 95 } 96 it=s.lower_bound((Dat){r,0,0,0}); 97 if(it->r!=r) 98 { 99 t=*it;s.erase(it);tn=0; 100 if(t.type==0) 101 { 102 SegT::split(1,n,t.nd,tn,r-t.l+1); 103 s.insert((Dat){t.r,r+1,t.nd,0}); 104 s.insert((Dat){r,t.l,tn,0}); 105 } 106 else 107 { 108 SegT::split(1,n,t.nd,tn,t.r-r); 109 s.insert((Dat){t.r,r+1,tn,1}); 110 s.insert((Dat){r,t.l,t.nd,1}); 111 } 112 } 113 while(1) 114 { 115 it=s.lower_bound((Dat){l,0,0,0}); 116 if(it==s.end()||it->l>r) break; 117 t=*it;s.erase(it); 118 ansn=SegT::merge(ansn,t.nd); 119 } 120 return ansn; 121 } 122 int main() 123 { 124 SegT::init(); 125 int t,t2,i,idx,l,r,q; 126 scanf("%d%d",&n,&m); 127 for(i=1;i<=n;i++) 128 { 129 scanf("%d",&t); 130 t2=SegT::getnode(); 131 SegT::addx(t,t2); 132 s.insert((Dat){i,i,t2,0}); 133 } 134 while(m--) 135 { 136 scanf("%d%d%d",&idx,&l,&r); 137 t=split_node(l,r); 138 s.insert((Dat){r,l,t,idx}); 139 } 140 scanf("%d",&q); 141 t=split_node(q,q); 142 printf("%d",SegT::query_kth(1,t)); 143 return 0; 144 }