题解 CF1771B Hossam and Friends

大家好,我是 CQ-C2024 蒟蒻 CJH。

题意

给定 $n$ 个数和 $m$ 个关系,每个关系的 $x$ 和 $y$ 不能出现在同一段中,请问有多少个连续子段符合要求。

分析题目

设 $a_i$ 为以 $i$ 为起点能符合要求的最远的终点,显然每个初始的终点都为 $n$。

当每给出一个关系 $x$ 和 $y$ 时,我们更新 $a_x=\min(a_x,y-1)$。

意思就是以 $x$ 为起点,如果原来的终点比现在的终点远,那么更新,因为终点过了 $y-1$ 就不符合要求了。

处理完 $m$ 个要求之后,从大到小枚举 $1 \le i <n$ 更新 $a_i = \min(a_i,a_{i+1})$。因为在 $i$ 之前的值都会受到 $a_i$ 的限制。

所以最终答案为 $\sum\limits_{i=1}^n{a_i-i+1}$,一定要加一,因为一个数本身也是符合要求的一个段

代码

//the code is from chenjh
#include<bits/stdc++.h>
using namespace std;
int a[100001];
void solve(){
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) a[i]=n;//能到的最远点设为 n。
    int x,y;
    while(m--){
        scanf("%d%d",&x,&y);
        if(x>y) swap(x,y);//此操作保证 x<y。
        a[x]=min(a[x],y-1);//更新答案。
    }
    for(int i=n-1;i>=1;i--)//从大到小!
        a[i]=min(a[i],a[i+1]);//更新限制。
    long long ans=0;
    for(int i=1;i<=n;i++)
        ans+=a[i]-i+1;//最远点减起点加一。
    printf("%lld\n",ans);
}
int main(){
    int t;scanf("%d",&t);
    while(t--) solve();
    return 0;
}
posted @ 2022-12-12 09:26  Chen_Jinhui  阅读(17)  评论(0)    收藏  举报  来源