CodeForces 652C Foe Pairs(思维题)

传送门:http://codeforces.com/problemset/problem/652/C

题意:

给出一个含有n个数的排列,给出m组数对(ai,bi),问n中有多少个区间是不包含任意一个数对的? (1<=n,m<=3e5, 1<=ai,bi<=n, ai≠ bi)

 

例如:第一组样例:区间[1,3]是含有第一个数对(3,2),区间[1,4]两个数对都包含,所以这两个区间是不计算的。答案是[1,1],[2,2],[3,3],[4,4],[1,2]这5个区间

 

思路:

  用一个数组f[]记录每个位置可以延伸的最大右端点。这样可以根据数组f[],遍历每个位置i,计算以i为左区间而不包含任意数对的区间个数,达到计算全部区间的效果。

 

  先对每个数对的所在左区间更新可达最大右端点。

  再从后往前再更新一次,使得左边点的延伸最大右端点一定是 小于等于任意右边点的延伸最大右端点。使得中间不包含任意数对。

  最后遍历计算所以区间。

 

代码:

#include<algorithm>
#include<cstdio>
#include<cstring>
#include<queue>
#define inf 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int maxn=3e5+100;
int f[maxn],p[maxn];

int main()
{
    int n,m,x,y;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&x);
        f[i]=n;//初始化可延伸右端点为n 
        p[x]=i;//记录每个数的位置 
    }
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&x,&y);
        int l=min(p[x],p[y]);//得到每个数对的左右区间 
        int r=max(p[x],p[y]);
        f[l]=min(f[l],r-1);//记录每个左端点可达最大延伸右端点 
    }    
    for(int i=n-1;i>=1;i--)
    {
        f[i]=min(f[i],f[i+1]);//更新每个位置的可达最大右端点 
    }
    ll ans=0;
    for(int i=1;i<=n;i++)
        ans+=f[i]-i+1;//计算以i为左区间,可以不包含任意数对的区间个数 
    printf("%lld\n",ans);
} 
posted @ 2020-01-07 14:42  怀揣少年梦.#  阅读(182)  评论(0编辑  收藏  举报