题解:P11203 [JOIG 2024] 感染シミュレーション / Infection Simulation
提供一种比较不要脑子的树套树做法。
先把每个问题拆成两个子问题。子问题一:求出连续感染的最长区间。子问题二:求和连续感染区间有交且交大于
那么显然是要先离线下来的,对于子问题一,左端点排序,先去掉完全被包含的区间,然后处理出每个区间到下一个区间交的大小,做倍增就可以了。
子问题二分为三种情况:左边交(
其他条件显然可以做二维偏序,除了
时间复杂度为
:::info[代码]
#include<bits/stdc++.h>
#define fst first
#define sec second
#define mkp(a,b) make_pair(a,b)
using namespace std;
typedef pair<int,int> pii;
const int maxn=2e5+5;
const int maxm=1e6+5;
const int inf=1e9+1;
void read(int& x){
char c; while((c=getchar())<48); x=c-48;
while((c=getchar())>47) x=(x<<3)+(x<<1)+c-48;
}
int t[maxm*20],ls[maxm*20],rs[maxm*20],tot=0,n,q,m;
void update(int x,int p,int u,int l=1,int r=m){
if(l==r){ t[u]+=p; return; }
int mid=l+r>>1;
if(x<=mid){
if(!ls[u]) ls[u]=++tot;
update(x,p,ls[u],l,mid);
}
else{
if(!rs[u]) rs[u]=++tot;
update(x,p,rs[u],mid+1,r);
}
t[u]=t[ls[u]]+t[rs[u]];
}
int query(int L,int R,int u,int l=1,int r=m){
if(r<L||l>R||(!u)) return 0;
if(l>=L&&r<=R) return t[u];
int mid=l+r>>1;
return query(L,R,ls[u],l,mid)+query(L,R,rs[u],mid+1,r);
}
int rt[maxm];
void add(int L,int R){
for(int i=L;i<=m;i+=i&(-i)) update(R,1,rt[i]);
}
int qin(int L,int R){
int ans=0;
for(int i=m;i>=1;i-=i&(-i)) ans+=query(1,R,rt[i]);
for(int i=L-1;i>=1;i-=i&(-i)) ans-=query(1,R,rt[i]);
return ans;
}
int qout(int L,int R){
int ans=0;
for(int i=L;i>=1;i-=i&(-i)) ans+=query(R,m,rt[i]);
return ans;
}
struct node{
int l,r,x,tp;
bool operator<(node a){
if(x==a.x) return a.tp==0&&tp==0 ? 0 : tp==0;
else return x>a.x;
}
};
int f[maxn][21],g[maxn][21],ans[maxn],lst[maxn];
pii a[maxn],b[maxn]; vector<node> v;
int main(){
read(n);
for(int i=1;i<=n;i++) read(a[i].fst),read(a[i].sec),a[i].sec=-a[i].sec,b[i]=a[i];
sort(a+1,a+n+1); int now=1,p=1; vector<int> vi;
for(int i=1;i<=n;i++) a[i].sec=-a[i].sec;
while(now<=n){
while(p<=n&&a[p].sec<=a[now].sec) ++p; vi.push_back(now);
f[now][0]=p,g[now][0]=(p>n||a[now].sec<=a[p].fst ? -1 : a[now].sec-a[p].fst),now=p;
}
for(int i=1;i<=20;i++){
for(int j : vi){
f[j][i]=f[f[j][i-1]][i-1],g[j][i]=min(g[j][i-1],g[f[j][i-1]][i-1]);
}
}
for(int i=1;i<=n;i++) lst[i]=(g[i][0] ? i : lst[i-1]);
for(int i=1;i<=n;i++) v.push_back((node){a[i].fst,a[i].sec,a[i].sec-a[i].fst,0});
for(int i=1;i<=n;i++) a[i].sec=-a[i].sec;
read(q);
for(int i=1;i<=q;i++){
int p,x; read(p),read(x);
p=lower_bound(a+1,a+n+1,b[p])-a;
if(-a[p].sec-a[p].fst<x){ ans[i]=1; continue; }
int now=lst[p];
for(int i=20;i>=0;i--){
if(g[now][i]>=x) now=f[now][i];
}
int L=a[p].fst,R=-a[now].sec;
v.push_back((node){L-1,L+x,x,i});
v.push_back((node){R-x,R+1,x,i});
v.push_back((node){L,R,x,-i});
}
sort(v.begin(),v.end());
vector<int> c;
for(node i : v) c.push_back(i.l),c.push_back(i.r);
sort(c.begin(),c.end()),c.erase(unique(c.begin(),c.end()),c.end()),m=c.size();
for(int i=0;i<(int)v.size();i++){
v[i].l=lower_bound(c.begin(),c.end(),v[i].l)-c.begin()+1;
v[i].r=lower_bound(c.begin(),c.end(),v[i].r)-c.begin()+1;
}
for(int i=1;i<=m;i++) rt[i]=++tot;
for(node i : v){
if(i.tp==0) add(i.l,i.r);
else if(i.tp<0) ans[-i.tp]+=qin(i.l,i.r);
else if(i.tp>0) ans[i.tp]+=qout(i.l,i.r);
}
for(int i=1;i<=q;i++) printf("%d\n",ans[i]);
return 0;
}
:::