洛谷 P2824 [HEOI2016/TJOI2016]排序 (线段树合并)

(另外:题解中有一种思路很高妙而且看上去可以适用一些其他情况的离线方法)


线段树合并&复杂度的简单说明:https://blog.csdn.net/zawedx/article/details/51818475

调用一次合并函数的时间是常数,
而合并函数每调用一次就会删掉一个点,
所以合并的总代价为删掉的点数和,

或者理解为:

https://wenku.baidu.com/view/88f4e134e518964bcf847c95.html

所以好像要合并就不能可持久化?(指保留每一个版本,在合并后仍旧保留合并前的版本)(不确定)

(部分的可持久化应该是可以的,就是在每次合并后保留合并前的版本,但合并前的版本不能再次拿去合并了)

(就是在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 }
View Code

删了一些奇怪调试代码之后的代码:

  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 }
posted @ 2018-04-22 12:28  hehe_54321  阅读(651)  评论(0编辑  收藏  举报
AmazingCounters.com