先对$c_{i}$离散到$[0,n]$上,并令$a_{i},b_{i},d_{i},e_{i}$对应到第一个大于等于他的数
考虑若$a_{n+1}$和$b_{n+1}$也已经确定如何做:
有一个$o(2^{n})$的暴力,即暴力确定每一个数是选择$a_{i}$还是$b_{i}$,记这些数依次为$p_{i}$,贪心去匹配,即将两者从小到大排序后有$p_{i}le c_{i}$
事实上,可以通过以下方式来判定:对于一个初始为0的数组,对所有$[p_{i},n]$加1,对所有$[c_{i},n]$减1,合法当且仅当所有位置都非负
证明:若$p_{i}le c_{i}$,必然非负,同时若存在非负的位置$x$,即$sum[xge p_{i}]-[xge c_{i}]<0$,对两者排序后,有$p_{i}中第一个大于x的位置<c_{i}中第一个大于x的位置$,记前者为$k$,则$p_{k}>xge c_{k}$
接下来,先全部令$p_{i}=a_{i}$,此时会有若干个位置小于0,然后可以对$[b_{i},a_{i})$这个区间加1,即表示令$p_{i}=$改为选择$b_{i}$,选择尽量少的区间使得最终非负(特别的,若$b_{i}>a_{i}$一定不会选择,删去此类区间)
同样可以贪心,即对于$k=max_{a_{i}<0}i$(若不存在即结束),必然选择包含$k$且左端点最小的区间,重复此过程,通过set维护最小左端点即可得到最优解,复杂度为$o(qnlog_{2}n)$
证明:对$i$之后的位置加1没有意义,因此右端点可以对$i$取min,两个相互包含的区间取较大的区间更优(另外不一定要保证在左端点最小的同时右端点最大)
接下来,由于仅有$n+1$变化,不妨$o(2)$去枚举最后一个点的选择,之后相当于询问对某一个后缀全部加1后的答案,也可以看作这个后缀要求大于等于-1即可
类似的贪心,即对于$k=max_{a_{i}<-1}i$,必然选择包含$k$左端点最小的区间(不论对什么后缀加1)
证明:假设对$[x,n]$这个后缀加1,若$xle k$则$k=max_{a_{i}<0}i$,因此必然修改;若$x>k$则$k$之后至多只有一个操作包含$k$,因为对于这样一个操作以后$k$之后所有数都变得非负了,此时$a_{k}<0$,因此仍要对$k$修改
(这里并不一定选择左端点最小的,因为可能上次包含$k$的操作就是左端点最小的,但必然是选择的)
同样重复这个过程,选出必选的区间,此时所有位置都大于等于-1
此时我们从左到右,对$a_{i}=-1$的位置求出仅考虑$i$以前(包括$i$)的所有-1,那么必然选择包含$i$且左端点最小的区间,然后变成了一个前缀的子问题,记录一下答案即可
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 100005 4 vector<int>v[N]; 5 multiset<pair<int,int> >s; 6 int n,m,x,y,tot,a[N],b[N],c[N],f[N],ans[N]; 7 bool cmp(int x,int y){ 8 return x>y; 9 } 10 int find(int k){ 11 return lower_bound(c,c+n+1,k)-c; 12 } 13 void update(int l,int r,int p){ 14 f[r]+=p; 15 if (l)f[l-1]-=p; 16 } 17 int main(){ 18 scanf("%d",&n); 19 for(int i=1;i<=n;i++)scanf("%d%d",&a[i],&b[i]); 20 for(int i=0;i<=n;i++)scanf("%d",&c[i]); 21 scanf("%d",&m); 22 sort(c,c+n+1); 23 for(int i=0;i<=n;i++)update(find(c[i]),n,-1); 24 for(int i=1;i<=n;i++){ 25 b[i]=min(b[i],a[i]); 26 if (b[i]>c[n]){ 27 for(int i=1;i<=m;i++)printf("-1 "); 28 return 0; 29 } 30 if (a[i]>c[n]){ 31 update(find(b[i]),n,1); 32 tot++; 33 continue; 34 } 35 a[i]=find(a[i]); 36 b[i]=find(b[i]); 37 update(a[i],n,1); 38 if (b[i]<a[i])v[a[i]-1].push_back(b[i]); 39 } 40 for(int i=0;i<=n;i++)sort(v[i].begin(),v[i].end(),cmp); 41 int sum=0; 42 for(int i=n;i>=0;i--){ 43 sum+=f[i]; 44 for(int j=0;j<v[i].size();j++)s.insert(make_pair(v[i][j],i)); 45 while (sum<-1){ 46 if ((!s.size())||((*s.begin()).first>i)){ 47 for(int i=1;i<=m;i++)printf("-1 "); 48 return 0; 49 } 50 int k=(*s.begin()).second; 51 s.erase(s.begin()); 52 tot++; 53 update(v[k].back(),k,1); 54 v[k].pop_back(); 55 sum++; 56 } 57 } 58 for(int i=n;i;i--)f[i-1]+=f[i]; 59 for(int i=0;i<=n;i++)v[i].clear(); 60 while (!s.empty()){ 61 v[(*s.begin()).first].push_back((*s.begin()).second); 62 s.erase(s.begin()); 63 } 64 for(int i=0;i<=n;i++){ 65 for(int j=0;j<v[i].size();j++)s.insert(make_pair(i,v[i][j])); 66 if (f[i]>=0)ans[i]=ans[i-1]; 67 else{ 68 if (!s.size()){ 69 ans[i]=0x3f3f3f3f; 70 continue; 71 } 72 int k=(*s.begin()).first; 73 if (!k)ans[i]=1; 74 else ans[i]=ans[k-1]+1; 75 } 76 while ((s.size())&&((*s.begin()).second<=i))s.erase(s.begin()); 77 } 78 for(int i=1;i<=m;i++){ 79 scanf("%d%d",&x,&y); 80 int k=-1; 81 if (x<=c[n]){ 82 if (x<=c[0])k=max(k,n-tot+1); 83 else k=max(k,n-(ans[find(x)-1]+tot)+1); 84 } 85 if (y<=c[n]){ 86 if (y<=c[0])k=max(k,n-tot); 87 else k=max(k,n-(ans[find(y)-1]+tot)); 88 } 89 printf("%d ",k); 90 } 91 }