题解:P7968 [COCI 2021/2022 #2] Osumnjičeni
模拟赛 T3,感觉评不了紫。赛时因为忘调用 build没调出来……
题目大意:给你
有一个显然的贪心想法就是对于每个部分,尽可能让其越长越好,因为这样后面剩的的线段越少越不容易有交集,于是我们对于每个位置
考虑这个东西怎么求,由于交集运算具有单调性,也就是若
于是可以双指针求,那怎么判断加入一个区间会不会产生交集呢?由于我们已经扫了
求出
代码:
#include<bits/stdc++.h>
#define mid (l+r>>1)
using namespace std;
const int N=2e5+5;
int n,q,f[N][20],b[N<<1],l[N],r[N],m,ls[N<<2],rs[N<<2],sum[N<<2],cnt,tag[N<<2];
void build(int &u,int l,int r){u=++cnt;if(l==r) return;build(ls[u],l,mid),build(rs[u],mid+1,r);}
void pushup(int u){sum[u]=sum[ls[u]]+sum[rs[u]];}
void pushdown(int u,int l,int r){
sum[ls[u]]+=(mid-l+1)*tag[u],sum[rs[u]]+=(r-mid)*tag[u];
tag[ls[u]]+=tag[u],tag[rs[u]]+=tag[u],tag[u]=0;
}
void add(int u,int l,int r,int L,int R,int val){
if(L<=l&&r<=R){tag[u]+=val,sum[u]+=(r-l+1)*val;return;}
pushdown(u,l,r);
if(L<=mid) add(ls[u],l,mid,L,R,val);
if(mid<R) add(rs[u],mid+1,r,L,R,val);
pushup(u);
}
int query(int u,int l,int r,int L,int R){
if(L<=l&&r<=R) return sum[u];
pushdown(u,l,r);int res=0;
if(L<=mid) res+=query(ls[u],l,mid,L,R);
if(mid<R) res+=query(rs[u],mid+1,r,L,R);
return res;
}
int main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
cin>>n;
for(int i=1;i<=n;i++) cin>>l[i]>>r[i],b[++m]=l[i],b[++m]=r[i];
cin>>q;sort(b+1,b+1+m);m=unique(b+1,b+1+m)-b-1;build(b[0],1,m);
for(int i=1;i<=n;i++) l[i]=lower_bound(b+1,b+1+m,l[i])-b,r[i]=lower_bound(b+1,b+1+m,r[i])-b;
for(int i=1,j=0;i<=n;i++){
while(j<n&&!query(1,1,m,l[j+1],r[j+1])) j++,add(1,1,m,l[j],r[j],1);
f[i][0]=j+1,add(1,1,m,l[i],r[i],-1);
}
for(int k=1;k<=17;k++)for(int i=1;i<=n;i++) f[i][k]=f[f[i][k-1]][k-1];
for(int i=1,u,v;i<=q;i++){
cin>>u>>v;int ans=0;
for(int k=17;~k;k--) if(f[u][k]&&f[u][k]<=v) u=f[u][k],ans|=1<<k;
cout<<ans+1<<'\n';
}
return 0;
}