列表

详情


NC20302. [SCOI2015]国旗计划

描述

A国正在开展一项伟大的计划——国旗计划。这项计划的内容是边防战士手举国旗环绕边境线奔袭一圈。这 项计划需要多名边防战士以接力的形式共同完成,为此,国土安全局已经挑选了N名优秀的边防战上作为这 项计划的候选人。 
A国幅员辽阔,边境线上设有M个边防站,顺时针编号1至M。每名边防战士常驻两个边防站,并且善于在这两个边防站之间长途奔袭,我们称这两个边防站之间的路程是这个边防战士的奔袭区间。n名边防战士 都是精心挑选的,身体素质极佳,所以每名边防战士的奔袭区间都不会被其他边防战士的奔袭区间所包含。
现在,国十安全局局长希望知道,至少需要多少名边防战士,才能使得他们的奔袭区间覆盖全部的边境线, 从而顺利地完成国旗计划。不仅如此,安全局局长还希望知道更详细的信息:对于每一名边防战士,在他必须参加国旗计划的前提下,至少需要多少名边防战士才能覆盖全部边境线,从而顺利地完成国旗计划。

输入描述

第1行,包含2个正整数N,M,分别表示边防战士数量和边防站数量。
随后n行,每行包含2个正整数。其中第i行包含的两个正整数Ci、Di分别表示i号边防战士常驻的两个边防站编号,Ci号边防站沿顺时针方向至Di号边防站力他的奔袭区间。
数据保证整个边境线都是可被覆盖的。

输出描述

输出数据仅1行,需要包含n个正整数。其中,第j个正整数表示j号边防战士必须参加的前提下至少需要多少名边防战士才能顺利地完成国旗计划

示例1

输入:

4 8       
2 5         
4 7         
6 1          
7 3

输出:

3 3 4 3

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++(g++ 7.5.0) 解法, 执行用时: 267ms, 内存消耗: 37652K, 提交时间: 2023-08-10 16:52:33

#include <iostream>
#include <algorithm>
using namespace std;
const int N = 400010;
int n, m, f[17][N], ans[N / 2];
struct SECTION { int l, r, id; } s[N];
bool cmp(SECTION a, SECTION b) { return a.l < b.l; }
int query(int x) {
    int end = s[x].l + m, res = 0;
    // 从大到小倍增
    for (int i = 16, pos = x; i >= 0; i--)
        // 这里是小于号, 之后最后的区间统一 + 1 就好, 否则难以处理
        if (s[f[i][pos]].r < end)
            pos = f[i][pos], res += (1 << i);
    // 加上自己和下一个区间
    return res + 2;
}
signed main() {
    cin >> n >> m;
    // 复制一倍接到后面
    for (int i = 1; i <= n; i++) { 
        cin >> s[i].l >> s[i].r;
        if (s[i].r < s[i].l) s[i].r += m;
        s[i + n].l = s[i].l + m, s[i + n].r = s[i].r + m;
        s[i].id = i, s[i + n].id = i + n;
    }
    sort(s + 1, s + 1 + n + n, cmp);
    // 找当前区间的最优后继
    for (int i = 1, j = 1; i <= n + n; i++) {
        while (j <= n + n && s[j].l <= s[i].r) j++;
        f[0][i] = j - 1;
    }
    // 倍增预处理
    for (int i = 1; i <= 16; i++) 
        for (int j = 1; j <= n + n; j++) 
            f[i][j] = f[i - 1][f[i - 1][j]];
    for (int i = 1; i <= n; i++) ans[s[i].id] = query(i);
    for (int i = 1; i <= n; i++) cout << ans[i] << ' ';
    cout << endl;
    return 0;
}

C++(clang++ 11.0.1) 解法, 执行用时: 284ms, 内存消耗: 75248K, 提交时间: 2023-07-07 21:03:24

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
typedef long long ll;
ll n,m,st[20][N<<1],anss[N];
struct node{
	ll l,r,id;
}a[N<<1];
bool cmp(node x,node y){
	return x.l<y.l;
}
int main(){
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		ll l,r;
		cin>>l>>r;
		if(l>r){
			r+=m;
		}
		a[i].l=l;
		a[i].r=r;
		a[i].id=i;
	}
	sort(a+1,a+n+1,cmp);
	for(int i=1;i<=n;i++){
		a[i+n].l=a[i].l+m,a[i+n].r=a[i].r+m;
	}
	for(int i=1,j=1;i<=2*n;i++){
		while(j<=2*n&&a[j].l<=a[i].r){
			j++;
		}
		st[0][i]=j-1;
	}
	for(int i=1;i<=19;i++){
		for(int j=1;j<=2*n;j++){
			st[i][j]=st[i-1][st[i-1][j]];
		}
	}
	for(int i=1;i<=n;i++){
		ll up=a[i].l+m,ans=0,p=i;
		for(int j=19;j>=0;j--){
			if(st[j][p]&&a[st[j][p]].r<up){
				ans+=1<<j;
				p=st[j][p];
			}
		}
		anss[a[i].id]=ans+2;
	}
	for(int i=1;i<=n;i++){
		cout<<anss[i]<<" ";
	}
	return 0;
}

上一题