luogu4155 国旗计划 题解

把区间按照端点递增排序(左右都一样,因为没有包含关系)。断环为链求出每个区间 \(i\) 往右经过一个区间能到达的最远区间。注意只有 \(l<r\) 的区间才需要复制。

对于满足 \(l \le M\) 的区间,倍增求解覆盖 \([l,l+M]\) 即可。

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define uint unsigned long long
#define PII pair<int,int>
#define MP make_pair
#define fi first
#define se second
#define SET(a,b) memset(a,b,sizeof(a))
#define CPY(a,b) memcpy(a,b,sizeof(b))
#define rep(i,j,k) for(int i=(j);i<=(k);++i)
#define per(i,j,k) for(int i=(j);i>=(k);--i)
int read() {
	int a=0, f=1; char c=getchar();
	while(!isdigit(c)) {
		if(c=='-') f=-1;
		c=getchar();
	}
	while(isdigit(c)) a=a*10+c-'0', c=getchar();
	return a*f;
}
const int N=2e5+5;
int n, m, cnt, f[2*N][20], ans[N];
struct node { int l, r, id; } a[2*N];
bool operator<(node a,node b) { return a.l!=b.l? a.l<b.l:a.r<b.r; }
int calc(int x) {
	int r=a[x].l+m, t=0;
	for(int i=18;~i;--i) {
		if(f[x][i]&&a[f[x][i]].r<r) x=f[x][i], t|=1<<i;
	}
	return t+2;
    // 算上x与最后的那个区间
}
signed main() {
	n=read(), m=read();
	cnt=n;
	rep(i,1,n) {
		a[i].l=read(), a[i].r=read();
		a[i].id=i;
		if(a[i].l>a[i].r) a[i].r+=m;
		else a[++cnt]={a[i].l+m,a[i].r+m,a[i].id};
	}
	sort(a+1,a+cnt+1);
	a[cnt+1].r=1e15;
    // 特判情况从[1,m]跳到[m,2m]
	int p=0;
	rep(i,1,cnt) {
		while(p<=cnt&&a[p+1].l<=a[i].r) ++p;
        // 找到最后一个满足a[p].l<=a[i].r的区间p
        // 求区间而不是点,相当于离散化
		f[i][0]=p;
	}
	rep(j,1,18) rep(i,1,cnt) f[i][j]=f[f[i][j-1]][j-1];
	rep(i,1,cnt) if(a[i].l<=m) ans[a[i].id]=calc(i);
	rep(i,1,n) printf("%lld ",ans[i]);
}


luogu4155 国旗计划 题解
https://yozora0908.github.io/2022/lg4155-solution/
作者
yozora0908
发布于
2022年5月7日
许可协议