[loj2461]完美的队列

参考论文,这里一共写了论文中的3种做法,第一种做法为强制在线时的做法,第二种为时间复杂度略高的做法(前两种都无法通过),第三种为本题正解,并给出了一种理论复杂度更优的做法

1.做法1

情况1

$\forall 1\le i\le n,a_{i}=1$

此时相当于维护一个序列,要求支持区间覆盖&求值的种类数

考虑去将相邻且权值(操作编号)相同的缩为一个段,用set来维护这些段,具体来说,对于每一段维护一个起点以及权值,将其作为set中的一个二元组,按起点从小到大排序

(特别的,为了避免有空隙而无法被表示,初始假设所有元素都为0)

对于一个操作,也就是将起点在$[l,r]$中的元素删除,并加入$(l,now)$以及$(r+1,last)$即可(其中$now$指当前操作的权值,$last$指插入前起点不超过$r$且最大的二元组的权值

(若已经存在以$r+1$为起点的二元组,则不插入$(r+1,last)$)

暴力删除即可,显然由于每一次至多产生两个元素,因此总时间复杂度为$o(n\log n)$

另外,关于答案的维护,直接统计所有二元组中每一个非0权值各有几个,在修改时维护即可

情况2

$\forall 1\le i\le n,a_{i}=k$

延续之前的做法,考虑去维护$k$个set

具体来说,将所有队列中的元素按队尾对齐,然后对于纵向的每一列维护一个set,每一次本要删除的元素加入下一个set中即可(对于最后一个set直接删除)

在加入下一个set时,我们要将所有元素一起插入,即先将其作为一个整体的$[l,r]$插入下一个set中,再将其中具体的每一段插入,避免新建过多节点

时间复杂度上,即每次操作至多产生$2k$个元素,且每一个元素至多被后移$k$次,因此总复杂度为$o(k^{2}n\log n)$

这个做法可以优化,如果通过splay来手动实现set,将这个区间在splay中分离出来,并直接接入到下一个中即可,这样的删除就不是均摊,而是每一次操作严格操作$k$次,总复杂度为$o(kn\log n)$

情况3

$\forall 1\le i\le n,a_{i}\le k$

此时先将其作为$\forall 1\le i\le n,a_{i}=k$来做,并预处理ST表来支持区间最小值,当某一个区间内$a_{i}$的最大值都小于当前set的编号则将其权值改为0(统计的是非0权值)

这样我们需要对所有操作的区间挨个检验,那么之前使用splay来优化并没有意义,仍为$o(k^{2}n\log n)$

考虑对每一个二元组再加一个权值,表示其区间内$a_{i}$的最大值,并用splay维护子树内的最小值,当发现存在最小值<set的编号,则找到最小值来源并删除即可

此时,由于每一个区间在被删除时才会有贡献,总复杂度变为$o(kn\log n)$

情况4

$\sum_{i=1}^{n}a_{i}\le 10^{6}$

这一情况下,将$a_{i}$分为两部分:

1.对于$a_{i}\le K$,将这些位置提出来变为一个另一个问题去做

2.对于$a_{i}>K$,这些位置数不超过$\frac{10^{6}}{K}$,每一次操作暴力检验是否影响到并插入即可

复杂度为$o(Kn\log n+\frac{10^{6}n}{K})$,取$K=\sqrt{\frac{10^{6}}{\log n}}$,复杂度即为$o(n\sqrt{10^{6}\log n})$,常数略卡

(实际情况下,由于空间问题,只能取$K=30$)

代码

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 #define N 100005
  4 #define s(p) f[k].ch[p]
  5 struct node{
  6     int fa,ch[2],st,ed,val,lim,mn;
  7 }f[N*61];
  8 vector<int>v;
  9 queue<int>q[N];
 10 int V,K,n,m,l,r,x,ans,a[N],Log[N],ST[N][21],rt[N],tot[N];
 11 void add(int k){
 12     if (++tot[k]==1)ans++;
 13 }
 14 void dec(int k){
 15     if (--tot[k]==0)ans--;
 16 }
 17 int get_max(int x,int y){
 18     int p=Log[y-x+1];
 19     return min(max(ST[x][p],ST[y-(1<<p)+1][p]),K);
 20 }
 21 bool pd(int k){
 22     return f[f[k].fa].ch[1]==k;
 23 }
 24 int New(int st,int ed,int val){
 25     int k=++V;
 26     f[k].fa=s(0)=s(1)=0;
 27     f[k].st=st,f[k].ed=ed,f[k].val=val;
 28     if (!val)f[k].lim=f[k].mn=K+1;
 29     else{
 30         f[k].lim=f[k].mn=get_max(st,ed);
 31         add(val);
 32     }
 33     return k;
 34 }
 35 void up(int k){
 36     f[k].mn=min(min(f[s(0)].mn,f[s(1)].mn),f[k].lim);
 37 }
 38 void connect(int k,int p,int u){
 39     f[u].fa=k;
 40     if (k){
 41         s(p)=u;
 42         up(k);
 43     }
 44 }
 45 void rotate(int k){
 46     int fa=f[k].fa,ga=f[fa].fa,p=pd(k);
 47     connect(ga,pd(fa),k);
 48     connect(fa,p,s(p^1));
 49     connect(k,(p^1),fa);
 50 }
 51 void splay(int k,int fa){
 52     while (f[k].fa!=fa){
 53         int i=f[k].fa;
 54         if (f[i].fa!=fa){
 55             if (pd(k)==pd(i))rotate(i);
 56             else rotate(k);
 57         }
 58         rotate(k);
 59     }
 60 }
 61 int find1(int &k,int x){
 62     int i=k,pos=0;
 63     while (i){
 64         if (f[i].st>x)i=f[i].ch[0];
 65         else{
 66             pos=i;
 67             i=f[i].ch[1];
 68         }
 69     }
 70     if (i){
 71         splay(i,f[k].fa);
 72         k=i;
 73     }
 74     return pos;
 75 }
 76 int find2(int &k,int x){
 77     int i=k,pos=0;
 78     while (i){
 79         if (f[i].st<=x)i=f[i].ch[1];
 80         else{
 81             pos=i;
 82             i=f[i].ch[0];
 83         }
 84     }
 85     if (i){
 86         splay(i,f[k].fa);
 87         k=i;
 88     }
 89     return pos;
 90 }
 91 void add(int &k,int x){
 92     int p=find1(k,f[x].st);
 93     if (!p){
 94         connect(x,1,k);
 95         k=x;
 96     }
 97     else{
 98         splay(p,f[k].fa);
 99         k=p;
100         if (s(1))connect(x,1,s(1));
101         connect(k,1,x);
102     }
103 }
104 void del(int &k,int x){
105     splay(x,0);
106     k=x;
107     dec(f[k].val);
108     f[k].val=0;
109     f[k].lim=K+1;
110     up(k);
111 }
112 int main(){
113     f[0].val=f[0].mn=0x3f3f3f3f;
114     scanf("%d%d",&n,&m);
115     for(int i=2;i<=n;i++)Log[i]=Log[i>>1]+1;
116     for(int i=1;i<=n;i++)scanf("%d",&a[i]);
117     K=30;
118     for(int i=1;i<=n;i++)
119         if (a[i]>K)v.push_back(i);
120     for(int i=n;i;i--){
121         ST[i][0]=a[i];
122         for(int j=1;j<=20;j++)ST[i][j]=max(ST[i][j-1],ST[min(i+(1<<j-1),n+1)][j-1]);
123     }
124     for(int i=1;i<=K;i++)rt[i]=New(1,n,0);
125     for(int i=1;i<=m;i++){
126         scanf("%d%d%d",&l,&r,&x);
127         int ll=lower_bound(v.begin(),v.end(),l)-v.begin();
128         int rr=upper_bound(v.begin(),v.end(),r)-v.begin()-1;
129         for(int j=ll;j<=rr;j++){
130             add(x);
131             q[j].push(x);
132             if (q[j].size()>a[v[j]]){
133                 dec(q[j].front());
134                 q[j].pop();
135             }
136         }
137         rt[0]=New(l,r,x);
138         for(int j=1;j<=K;j++){
139             int p1=find1(rt[j],l-1);
140             if ((p1)&&(l<=f[p1].ed)){
141                 if (get_max(l,f[p1].ed)<j)add(rt[j],New(l,f[p1].ed,0));
142                 else add(rt[j],New(l,f[p1].ed,f[p1].val));
143                 splay(p1,0);
144                 f[p1].ed=l-1;
145                 rt[j]=p1;
146                 if (f[p1].val){
147                     f[p1].lim=get_max(f[p1].st,f[p1].ed);
148                     up(p1);
149                     if (f[p1].lim<j)del(rt[j],p1);
150                 }
151             }
152             int p2=find1(rt[j],r);
153             if ((r<n)&&(r<f[p2].ed)){
154                 if (get_max(r+1,f[p2].ed)<j)add(rt[j],New(r+1,f[p2].ed,0));
155                 else add(rt[j],New(r+1,f[p2].ed,f[p2].val));
156                 splay(p2,0);
157                 f[p2].ed=r;
158                 rt[j]=p2;
159                 if (f[p2].val){
160                     f[p2].lim=get_max(f[p2].st,f[p2].ed);
161                     up(p2);
162                     if (f[p2].lim<j)del(rt[j],p2);
163                 }
164             }
165             p2=find2(rt[j],r);
166             if (!p1){
167                 if (!p2)swap(rt[0],rt[j]);
168                 else{
169                     splay(p2,0);
170                     rt[j]=p2;
171                     int k=f[rt[j]].ch[0];
172                     connect(0,0,k);
173                     connect(rt[j],0,rt[0]);
174                     rt[0]=k;
175                 }
176             }
177             else{
178                 splay(p1,0);
179                 rt[j]=p1;
180                 if (!p2){
181                     int k=f[rt[j]].ch[1];
182                     connect(0,0,k);
183                     connect(rt[j],1,rt[0]);
184                     rt[0]=k;
185                 }
186                 else{
187                     splay(p2,rt[j]);
188                     int k=f[p2].ch[0];
189                     connect(0,0,k);
190                     connect(p2,0,rt[0]);
191                     rt[0]=k;
192                     up(rt[j]);
193                 }
194             }
195             while ((rt[0])&&(f[rt[0]].mn==j)){
196                 int k=rt[0];
197                 while (f[k].lim!=j){
198                     if (f[s(0)].mn==j)k=s(0);
199                     else k=s(1);
200                 }
201                 del(rt[0],k);
202             }
203         }
204         printf("%d\n",ans);
205     }
206 } 
View Code

 

 

 

2.做法2

基本思路

对于第$i$个操作,称其影响操作$j$当且仅当第$j$次操作结束后,第$i$次操作插入的数字还在队列中

其所影响的操作是一个以$i$为左端点的连续区间,以下记作$[i,end_{i}]$,而当我们(离线)求出这个区间,简单差分一下就可以$o(n)$求出最终答案,因此以下考虑如何求$end_{i}$

先考虑一个更简单的问题,如何判定$i$是否影响$j$(其中$i\le j$),有如下的暴力做法:

1.$\forall i+1\le k\le j$,对序列$a_{i}$的$[l_{k},r_{k}]$区间减1(从初始的$a$序列开始操作)

2.求出序列$a_{i}$的$[l_{i},r_{i}]$的区间最大值,若大于0即影响操作$j$(否则不影响)

区间减1以及区间最大值用线段树来维护,复杂度即为$o(n^{2}\log^{2}n)$,但无法通过

分块优化

考虑分块,设块大小为$K$,将过程分为以下两部分:

1.确定$end_{i}$在哪一个块中

这可以通过对每一个块首(记作$st$)出发向前遍历,遍历过程中维护线段树,因此遍历到$i$即可判定$i$是否影响$st$,对于$i$影响的$st$中最大的$st$所在块即为$end_{i}$所在块

(特别的,若不存在则$end_{i}$在$i$所在块)

由于每一个块首遍历都要$o(n\log n)$的复杂度,总复杂度即$o(\frac{n^{2}}{K}\log n)$

2.求出$end_{i}$具体的位置

先枚举块,然后将$end_{i}$在该块中的询问取出,并从大到小排序

仍然从块首向前遍历,当遍历到的位置的答案在这个块中,将右端点向右移动,直至未被影响或到达块尾,即可求出该$end_{i}$,然后再将右端点移回块首

每一个操作复杂度为$o(K\log n)$(块首遍历与之前相同,不考虑),总复杂度即$(Kn\log n)$

综上,复杂度为$o(\frac{n^{2}}{K}\log n+Kn\log n)$,取$K=\sqrt{n}$即可做到$o(n\sqrt{n}\log n)$的复杂度

代码

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define N 100005
 4 #define L (k<<1)
 5 #define R (L+1)
 6 #define mid (l+r>>1)
 7 struct Operator{
 8     int l,r,x;
 9 }op[N];
10 vector<int>v[N],v_add[N],v_dec[N];
11 int K,n,m,ans_tot,a[N],bl[N],st[N],ed[N],f[N<<2],tag[N<<2],ans[N],tot[N],true_ans[N];
12 void add(int k){
13     if (++tot[k]==1)ans_tot++;
14 }
15 void dec(int k){
16     if (--tot[k]==0)ans_tot--;
17 }
18 void upd(int k,int x){
19     tag[k]+=x,f[k]+=x;
20 }
21 void down(int k){
22     if (tag[k]){
23         upd(L,tag[k]);
24         upd(R,tag[k]);
25         tag[k]=0;
26     }
27 }
28 void build(int k,int l,int r){
29     tag[k]=0;
30     if (l==r){
31         f[k]=a[l];
32         return;
33     }
34     build(L,l,mid);
35     build(R,mid+1,r);
36     f[k]=max(f[L],f[R]);
37 }
38 void update(int k,int l,int r,int x,int y,int z){
39     if ((l>y)||(x>r))return;
40     if ((x<=l)&&(r<=y)){
41         upd(k,z);
42         return;
43     }
44     down(k);
45     update(L,l,mid,x,y,z);
46     update(R,mid+1,r,x,y,z);
47     f[k]=max(f[L],f[R]);
48 }
49 int query(int k,int l,int r,int x,int y){
50     if ((l>y)||(x>r))return f[0];
51     if ((x<=l)&&(r<=y))return f[k];
52     down(k);
53     return max(query(L,l,mid,x,y),query(R,mid+1,r,x,y));
54 }
55 int main(){
56     f[0]=-0x3f3f3f3f;
57     scanf("%d%d",&n,&m);
58     for(int i=1;i<=n;i++)scanf("%d",&a[i]);
59     for(int i=1;i<=m;i++)scanf("%d%d%d",&op[i].l,&op[i].r,&op[i].x);
60     K=(int)sqrt(m);
61     for(int i=1;i<=m;i++)bl[i]=(i-1)/K+1;
62     for(int i=1;i<=bl[m];i++){
63         st[i]=(i-1)*K+1;
64         ed[i]=min(i*K,m);
65     }
66     for(int i=1;i<=bl[m];i++){
67         build(1,1,n);
68         for(int j=ed[i];j;j--){
69             if (query(1,1,n,op[j].l,op[j].r)>0)ans[j]=i;
70             if (j<=st[i])update(1,1,n,op[j].l,op[j].r,-1);
71         }
72     }
73     for(int i=1;i<=m;i++)v[ans[i]].push_back(i);
74     for(int i=1;i<=bl[m];i++){
75         build(1,1,n);
76         for(int j=ed[i];v[i].size();j--){
77             if (v[i].back()==j){
78                 for(ans[j]=max(st[i],j);ans[j]<ed[i];ans[j]++){
79                     update(1,1,n,op[ans[j]+1].l,op[ans[j]+1].r,-1);
80                     if (query(1,1,n,op[j].l,op[j].r)<=0)break;
81                 }
82                 for(int k=max(st[i],j);(k<=ans[j])&&(k<ed[i]);k++)update(1,1,n,op[k+1].l,op[k+1].r,1);
83                 v[i].pop_back();
84             }
85             if (j<=st[i])update(1,1,n,op[j].l,op[j].r,-1);
86         }
87     }
88     for(int i=1;i<=m;i++){
89         v_add[i].push_back(op[i].x);
90         v_dec[ans[i]].push_back(op[i].x);
91     }
92     for(int i=1;i<=m;i++){
93         for(int j=0;j<v_add[i].size();j++)add(v_add[i][j]);
94         printf("%d\n",ans_tot);
95         for(int j=0;j<v_dec[i].size();j++)dec(v_dec[i][j]);
96     }
97 } 
View Code

 

 

 

 

3.做法3

基本思路

如果可以证明$\forall 1\le i<m,end_{i}\le end_{i+1}$,根据单调性,可以在$o(n\log n)$的时间内求出$end_{i}$

但这件事情显然是错误的,不过若第$i$次操作和第$j$次操作的区间相同($i<j$),则$end_{i}\le end_{j}$

由此,我们想到将一个操作的区间拆开,并对相同的区间用单调性来做

考虑分块,同样以$K$为大小进行分块,将每一个操作拆为若干个整块操作和至多两个非整块操作,那么对于操作$i$的$end_{i}$,也就是所有拆出的操作的$end$的最大值

由于一个操作至多影响一个块,根据两个块之间的独立性,将每一个块的操作分别处理

具体来说,这个块内的操作分为整块操作和非整块操作,以下分别来处理

整块操作

先来说一下关于复杂度的描述:

记$n_{1}$为块内整块操作数,$n_{2}$为非整块操作数,用$n_{1}$和$n_{2}$来描述块内操作复杂度,并根据$\sum n_{1}=o(\frac{n^{2}}{K})$和$\sum n_{2}=o(n)$来求出总时间复杂度

对于整块操作,也就是操作区间相同,即可以根据单调性来做,块内复杂度为$o((n_{1}+n_{2})\log n)$,总时间复杂度即$o(\frac{n^{2}}{K}\log n)$

考虑优化,对整块操作直接在线段树外打懒标记即可,这样块内复杂度即降为$o(n_{1}+n_{2}\log n)$,累加后也就是$o(\frac{n^{2}}{K}+n\log n)$,可以忽略$o(n\log n)$,即$o(\frac{n^{2}}{K})$

另外,我们以此法找到的是块内的$end_{i}$,如果算上块外,应该取块内下一个操作(如果不存在则可以忽略或设置为$m+1$)减1作为其$end_{i}$,下面非整块操作相同

非整块操作

我们将这些操作再继续拆分,拆分为$K$个操作,这些操作同样可以用单调性来做

但这里的判定与之前不同,我们要加上我们所忽略了的整块操作,通过前缀和+差分来求出区间内的整块操作数即可计算

对于一个队列显然就不需要线段树了,复杂度为$o(Kn_{2}+n)$(这个$n$是前缀和+差分的复杂度)

我们现在对于$i$操作所找到的非整块操作,实际上是在$end_{i}$之前(包括$end_{i}$自身)第一个非整块操作,通过预处理每一个第$i$个整块操作以及之前的前缀和,可以$o(1)$找到$end_{i}$

综上,块内复杂度为$o(Kn_{2}+n)$,总复杂度为$o(Kn+\frac{n^{2}}{K})$

综合整块操作,复杂度仍然是$o(Kn+\frac{n^{2}}{K})$,取$K=\sqrt{n}$可做到$o(n\sqrt{n})$的复杂度

(另外,由于空间问题,需要将每一次继续拆分的$K$个操作所记录到的$K$个vector来重复利用)

代码

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 #define N 100005
  4 #define L (k<<1)
  5 #define R (L+1)
  6 #define mid (l+r>>1)
  7 struct Operator{
  8     int l,r,x;
  9 };
 10 vector<Operator>op[N];
 11 vector<int>v_all,v[N],v_add[N],v_dec[N];
 12 int K,n,m,l,r,ans_tot,a[N],bl[N],st[N],ed[N],val[N],sum[N],f[N<<2],tag[N<<2],ans[N],tot[N];
 13 void add(int k){
 14     if (++tot[k]==1)ans_tot++;
 15 }
 16 void dec(int k){
 17     if (--tot[k]==0)ans_tot--;
 18 }
 19 void upd(int k,int x){
 20     tag[k]+=x,f[k]+=x;
 21 }
 22 void down(int k){
 23     if (tag[k]){
 24         upd(L,tag[k]);
 25         upd(R,tag[k]);
 26         tag[k]=0;
 27     }
 28 }
 29 void build(int k,int l,int r){
 30     tag[k]=0;
 31     if (l==r){
 32         f[k]=a[l];
 33         return;
 34     }
 35     build(L,l,mid);
 36     build(R,mid+1,r);
 37     f[k]=max(f[L],f[R]);
 38 }
 39 void update(int k,int l,int r,int x,int y,int z){
 40     if ((l>y)||(x>r))return;
 41     if ((x<=l)&&(r<=y)){
 42         upd(k,z);
 43         return;
 44     }
 45     down(k);
 46     update(L,l,mid,x,y,z);
 47     update(R,mid+1,r,x,y,z);
 48     f[k]=max(f[L],f[R]);
 49 }
 50 int main(){
 51     f[0]=-0x3f3f3f3f;
 52     scanf("%d%d",&n,&m);
 53     for(int i=1;i<=n;i++)scanf("%d",&a[i]);
 54     K=(int)sqrt(n);
 55     for(int i=1;i<=n;i++)bl[i]=(i-1)/K+1;
 56     for(int i=1;i<=bl[n];i++){
 57         st[i]=(i-1)*K+1;
 58         ed[i]=min(i*K,n);
 59     }
 60     for(int i=1;i<=m;i++){
 61         scanf("%d%d%d",&l,&r,&val[i]);
 62         if (bl[l]==bl[r])op[bl[l]].push_back(Operator{l,r,i});
 63         else{
 64             op[bl[l]].push_back(Operator{l,ed[bl[l]],i});
 65             op[bl[r]].push_back(Operator{st[bl[r]],r,i});
 66             for(int j=bl[l]+1;j<bl[r];j++)op[j].push_back(Operator{st[j],ed[j],i});
 67         }
 68     }
 69     for(int i=1;i<=bl[n];i++){
 70         build(1,st[i],ed[i]);
 71         v_all.clear();
 72         memset(sum,0,sizeof(sum));
 73         for(int j=0;j<=ed[i]-st[i];j++)v[j].clear();
 74         for(int j=0,k=0;j<op[i].size();j++){
 75             if (j)update(1,st[i],ed[i],op[i][j].l,op[i][j].r,1);
 76             if ((op[i][j].l==st[i])&&(op[i][j].r==ed[i])){
 77                 v_all.push_back(op[i][j].x);
 78                 sum[op[i][j].x]++;
 79                 while ((k<op[i].size())&&(f[1]>0)){
 80                     k++;
 81                     if (k<op[i].size())update(1,st[i],ed[i],op[i][k].l,op[i][k].r,-1);
 82                 }
 83                 if (k==op[i].size())ans[op[i][j].x]=m;
 84                 else ans[op[i][j].x]=max(ans[op[i][j].x],op[i][k].x-1);
 85             }
 86             else{
 87                 for(int t=op[i][j].l;t<=op[i][j].r;t++)v[t-st[i]].push_back(op[i][j].x);
 88             }
 89         }
 90         for(int j=1;j<m;j++)sum[j+1]+=sum[j];
 91         for(int j=0;j<=ed[i]-st[i];j++){
 92             int lim=a[j+st[i]];
 93             for(int k=0,t=0;k<v[j].size();k++){
 94                 while ((t<v[j].size())&&(t-k+sum[v[j][t]]-sum[v[j][k]]<lim))t++;
 95                 if (t<v[j].size()){
 96                     if (t-k+sum[v[j][t]]-sum[v[j][k]]==lim)ans[v[j][k]]=max(ans[v[j][k]],v[j][t]-1);
 97                     else ans[v[j][k]]=max(ans[v[j][k]],v_all[lim+sum[v[j][k]]-t+k]-1);
 98                 }
 99                 else{
100                     if (t-k+sum[m]-sum[v[j][k]]<=lim)ans[v[j][k]]=m;
101                     else ans[v[j][k]]=max(ans[v[j][k]],v_all[lim+sum[v[j][k]]-t+k]-1);
102                 }
103             }
104         }
105     }
106     for(int i=1;i<=m;i++){
107         v_add[i].push_back(val[i]);
108         v_dec[ans[i]].push_back(val[i]);
109     }
110     for(int i=1;i<=m;i++){
111         for(int j=0;j<v_add[i].size();j++)add(v_add[i][j]);
112         printf("%d\n",ans_tot);
113         for(int j=0;j<v_dec[i].size();j++)dec(v_dec[i][j]);
114     }
115 } 
View Code

线段树分治

事实上,这道题还可以做到更好的理论时间复杂度

考虑将区间用线段树去划分(类似于线段树分治的写法),用类似地方法处理,具体来说如下:

1.对于之前的整块操作,不能前缀和+差分以及暴力记录来查找,需要另外建立一棵线段树,并再返回时撤销即可,这里修改总复杂度为$o(n\log^{2}n)$,询问单次$o(\log n)$(包括求和以及查找)

2.对于每一个节点,将子树内所有操作都放在自己上并求出所有恰好覆盖该块,注意到这等价于线段树区间修改的复杂度,因此操作总量是$o(n\log n)$的,每一次需要修改限制以及在上面线段树查找,也是$o(n\log^{2}n)$

综上,我们得到了一个理论复杂度$o(n\log^{2}n)$,但其实际运行时间远劣于上面的分块

代码

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 #define N 100005
  4 #define L (k<<1)
  5 #define R (L+1)
  6 #define mid (l+r>>1)
  7 struct Operator{
  8     int l,r,x;
  9 };
 10 vector<Operator>op[N<<2];
 11 vector<int>v_add[N],v_dec[N];
 12 int n,m,l,r,ans_tot,a[N],val[N],lim[N<<2],tag[N<<2],sum[N<<2],ans[N],tot[N];
 13 void add(int k){
 14     if (++tot[k]==1)ans_tot++;
 15 }
 16 void dec(int k){
 17     if (--tot[k]==0)ans_tot--;
 18 }
 19 void upd(int k,int x){
 20     tag[k]+=x,lim[k]+=x;
 21 }
 22 void down(int k){
 23     if (tag[k]){
 24         upd(L,tag[k]);
 25         upd(R,tag[k]);
 26         tag[k]=0;
 27     }
 28 }
 29 void build(int k,int l,int r){
 30     tag[k]=0;
 31     if (l==r){
 32         lim[k]=a[l];
 33         return;
 34     }
 35     build(L,l,mid);
 36     build(R,mid+1,r);
 37     lim[k]=max(lim[L],lim[R]);
 38 }
 39 void update_lim(int k,int l,int r,int x,int y,int z){
 40     if ((l>y)||(x>r))return;
 41     if ((x<=l)&&(r<=y)){
 42         upd(k,z);
 43         return;
 44     }
 45     down(k);
 46     update_lim(L,l,mid,x,y,z);
 47     update_lim(R,mid+1,r,x,y,z);
 48     lim[k]=max(lim[L],lim[R]);
 49 }
 50 void update_cover(int k,int l,int r,int x,int y){
 51     sum[k]+=y;
 52     if (l==r)return;
 53     if (x<=mid)update_cover(L,l,mid,x,y);
 54     else update_cover(R,mid+1,r,x,y);
 55 }
 56 int query(int k,int l,int r,int x,int y){
 57     if ((l>y)||(x>r))return 0;
 58     if ((x<=l)&&(r<=y))return sum[k];
 59     return query(L,l,mid,x,y)+query(R,mid+1,r,x,y);
 60 }
 61 int find(int k,int l,int r,int x){
 62     if (l==r)return l;
 63     if (x<=sum[L])return find(L,l,mid,x);
 64     return find(R,mid+1,r,x-sum[L]);
 65 }
 66 void add(int k,int l,int r,int x,int y,int z){
 67     if ((l>y)||(x>r))return;
 68     op[k].push_back(Operator{max(l,x),min(r,y),z});
 69     if ((x<=l)&&(r<=y))return;
 70     add(L,l,mid,x,y,z);
 71     add(R,mid+1,r,x,y,z);
 72 }
 73 void dfs(int k,int l,int r){
 74     build(1,l,r);
 75     for(int i=0,j=0;i<op[k].size();i++){
 76         int t=op[k][i].x;
 77         if (i)update_lim(1,l,r,op[k][i].l,op[k][i].r,1);
 78         if ((op[k][i].l==l)&&(op[k][i].r==r)){
 79             while ((j<op[k].size())&&(lim[1]>query(1,1,m,t,op[k][j].x))){
 80                 j++;
 81                 if (j<op[k].size())update_lim(1,l,r,op[k][j].l,op[k][j].r,-1);
 82             }
 83             if (j==op[k].size()){
 84                 if (query(1,1,m,t,m)<lim[1])ans[t]=m;
 85                 else ans[t]=max(ans[t],find(1,1,m,lim[1]+query(1,1,m,1,t))-1);
 86             }
 87             else{
 88                 update_lim(1,l,r,op[k][j].l,op[k][j].r,1);
 89                 if (query(1,1,m,t,op[k][j].x)<lim[1])ans[t]=max(ans[t],op[k][j].x-1);
 90                 else ans[t]=max(ans[t],find(1,1,m,lim[1]+query(1,1,m,1,t))-1);
 91                 update_lim(1,l,r,op[k][j].l,op[k][j].r,-1);
 92             }
 93         }
 94     }
 95     for(int i=0;i<op[k].size();i++)
 96         if ((op[k][i].l==l)&&(op[k][i].r==r))update_cover(1,1,m,op[k][i].x,1);
 97     if (l<r){
 98         dfs(L,l,mid);
 99         dfs(R,mid+1,r);
100     }
101     for(int i=0;i<op[k].size();i++)
102         if ((op[k][i].l==l)&&(op[k][i].r==r))update_cover(1,1,m,op[k][i].x,-1);
103 }
104 int main(){
105     scanf("%d%d",&n,&m);
106     for(int i=1;i<=n;i++)scanf("%d",&a[i]);
107     for(int i=1;i<=m;i++){
108         scanf("%d%d%d",&l,&r,&val[i]);
109         add(1,1,n,l,r,i);
110     }
111     dfs(1,1,n);
112     for(int i=1;i<=m;i++){
113         v_add[i].push_back(val[i]);
114         v_dec[ans[i]].push_back(val[i]);
115     }
116     for(int i=1;i<=m;i++){
117         for(int j=0;j<v_add[i].size();j++)add(v_add[i][j]);
118         printf("%d\n",ans_tot);
119         for(int j=0;j<v_dec[i].size();j++)dec(v_dec[i][j]);
120     }
121 }
View Code

 

posted @ 2021-03-10 14:18  PYWBKTDA  阅读(274)  评论(0编辑  收藏  举报