#回滚莫队,链表#洛谷 6349 [PA2011] Kangaroos
分析
首先区间 \([l,r]\) 与 \([L,R]\) 相交当且仅当 \(l\leq R\) 且 \(L\leq r\)(其实就是完全覆盖或者有一端点在区间中)
而且坐标范围太大了,如果要离散的话就更容易考虑离线了(在线也许比较难写?)
如果单单莫队的话左右端点的移动会非常麻烦,考虑回滚莫队,固定左端点所在块。
询问区间分为端点同块或者不同块两种情况,对于端点同块的情况,如果给定区间完全覆盖块那么可以直接计算进去
不能完全覆盖的话其中一个端点肯定在询问区间中,直接从询问区间的左端点枚举到右端点加入新的给定区间即可。
不同块的话左端点所在块的右端点是固定的,那么完全覆盖可以先考虑覆盖左端点所在块的右端点,
那么剩下可行区间仍然其中一个端点在询问区间中,块外向右扩展端点,块内回滚即可,维护最长连续段可以用链表
代码
#include <cstdio>
#include <cctype>
#include <vector>
#include <algorithm>
#include <cmath>
using namespace std;
const int N=200011,M=331;
struct rec{
int l,r,rk;
bool operator <(const rec &t)const{
return r>t.r;
}
}a[N],st[N*5/2];
int n,Q,pos[N],L[M],R[M],bl,Ans[N],ans,Top,ls[N],rs[N];
pair<int,int>b[N]; vector<rec>K[M];
int iut(){
int ans=0,f=1; char c=getchar();
while (!isdigit(c)) f=(c=='-')?-f:f,c=getchar();
while (isdigit(c)) ans=ans*10+c-48,c=getchar();
return ans*f;
}
void print(int ans){
if (ans>9) print(ans/10);
putchar(ans%10+48);
}
void Max(int &x,int y){x=x>y?x:y;}
void add(int x){
if (ls[x]) return;
st[++Top]=(rec){x,0,ans},ls[x]=rs[x]=x,Max(ans,1);
if (ls[x-1]) st[++Top]=(rec){ls[x-1],rs[ls[x-1]],ans},st[++Top]=(rec){-rs[x],ls[rs[x]],ans},rs[ls[x-1]]=rs[x],ls[rs[x]]=ls[x-1],Max(ans,rs[ls[x]]-ls[rs[x]]+1);
if (rs[x+1]) st[++Top]=(rec){-rs[x+1],ls[rs[x+1]],ans},st[++Top]=(rec){ls[x],rs[ls[x]],ans},ls[rs[x+1]]=ls[x],rs[ls[x]]=rs[x+1],Max(ans,rs[ls[x]]-ls[rs[x]]+1);
}
void BackTrace(int TOP){
for (;Top>TOP;ans=st[Top--].rk)
if (st[Top].l<0) ls[-st[Top].l]=st[Top].r;
else if (st[Top].r) rs[st[Top].l]=st[Top].r;
else ls[st[Top].l]=rs[st[Top].l]=0;
}
int main(){
n=iut(),Q=iut(),bl=sqrt(2*n);
for (int i=1;i<=n;++i){
int l=iut(),r=iut();
b[i*2-1]=make_pair(l,i);
b[i*2]=make_pair(r,i);
}
sort(b+1,b+1+2*n);
for (int i=1;i<=2*n;++i)
if (a[b[i].second].l) a[b[i].second].r=i;
else a[b[i].second].l=i;
for (int i=1;i<=2*n;++i) pos[i]=(i-1)/bl+1;
for (int i=1;i<=2*n;++i) if (!L[pos[i]]) L[pos[i]]=i;
for (int i=2*n;i>=1;--i) if (!R[pos[i]]) R[pos[i]]=i;
for (int i=1;i<=Q;++i){
int l=iut(),r=iut();
l=lower_bound(b+1,b+1+2*n,make_pair(l,0))-b;
r=upper_bound(b+1,b+1+2*n,make_pair(r,n+1))-b-1;
if (r<1||l>2*n) continue;
K[pos[l]].push_back((rec){l,r,i});
}
for (int i=1;i<=pos[2*n];++i) if (!K[i].empty()){
for (int j=1;j<=n;++j)
if (a[j].l<L[i]&&R[i]<a[j].r) add(j);
sort(K[i].begin(),K[i].end());
int siz=K[i].size();
for (;siz&&K[i][siz-1].r<=R[i];--siz){
int TOP=Top;
for (int j=L[i];j<=R[i];++j)
if (a[b[j].second].l<=K[i][siz-1].r&&K[i][siz-1].l<=a[b[j].second].r)
add(b[j].second);
Ans[K[i][siz-1].rk]=ans,BackTrace(TOP);
}
BackTrace(0);
if (siz){
for (int j=1;j<=n;++j)
if (a[j].l<=R[i]&&R[i]<=a[j].r) add(j);
for (int now=R[i]+1;siz;--siz){
for (;now<=K[i][siz-1].r;++now) add(b[now].second);
int TOP=Top;
for (int j=R[i];j>=K[i][siz-1].l;--j) add(b[j].second);
Ans[K[i][siz-1].rk]=ans,BackTrace(TOP);
}
BackTrace(0);
}
}
for (int i=1;i<=Q;++i) print(Ans[i]),putchar(10);
return 0;
}
···