zoukankan      html  css  js  c++  java
  • 【2018黑龙江省赛】UPC-7218 A Sequence Game(莫队&离散化&RMQ ST表)

    题目描述
    One day, WNJXYK found a very hard problem on an Online Judge. This problem is so hard that he had been thinking about the solutions for a couple of days. And then he had a surprise that he misunderstood that problem and easily figured out a solution using segment tree. Now he still wonders that solution for the misread problem.
    There is a sequence with N positive integers A1,A2,…,An and M queries. Each query will give you an interval [L,R] and require an answer with YES / NO indicates that whether the numbers in this interval are continuous in its integer range.
    Let us assume that the maximal number in an interval is mx and the minimal number is mi. The numbers in this interval are continuous in its integer range means that each number from mi to mx appears at least once in this interval.

    输入
    The input starts with one line contains exactly one positive integer T which is the number of test cases. And then there are T cases follow.
    The first line contains two positive integers n,m which has been explained above.
    The second line contains n positive integers A1,A2,…,An.
    Then there will be m lines followed. Each line contains to positive numbers Li,Ri indicating that the i th query’s interval is [Li,Ri].

    输出
    For each test case, output m line.
    Each of following m lines contains a single string “YES”/ “NO” which is the answer you have got.

    样例输入
    2
    3 3
    3 1 2
    2 3
    1 3
    1 2
    5 3
    1 2 2 4 5
    1 5
    1 3
    3 3

    样例输出
    YES
    YES
    NO
    NO
    YES
    YES

    提示
    T=5
    1≤n≤100000
    1≤Ai≤10^9
    1≤m≤100000
    The input file is very large, so you are recommend to use scanf() and printf() for IO.
    题意: 给出一个长度为n的序列a,其中ai值小于等于1e9,有m次询问,每次询问给出一个区间[L,R],询问该区间内的最大值和最小值之间的数是否都至少出现过一次。

    题解: 首先是查找给出区间查找区间内最大值和最小值,这个用RMQ处理即可,然后是如何处理某个区间内出现的数的是否在最大最小值范围内,且一个不落,可以知道,统计一个区间内不同的数的个数,并且知道这个区间内最大值和最小值,就可以知道该区间内是否存在足够的数铺满最大最小值之间的数,因为区间大小已知,该区间内值不会超过或低于最大最小值,也就是说出现的值一定在范围内,然后不同的数的个数限定了是每个数只能至少出现一次,如果出现多次,除非该区间长度大于最大值减最小值,否则必须是每个数都出现过。用莫队算法维护即可。每次移动两个指针,计算每个值对该区间出现的不同数的数量的影响。
    因为值特别大,因此要做离散化,然后映射到标记数组中标记出现次数,出区间的值出现次数减少,减到0时不同数的数量减1,进区间的值,如果是第一次出现,不同数的数量加1,用于计算每个区间的结果。

    #include<bits/stdc++.h>
    #define LL long long
    #define M(a,b) memset(a,b,sizeof a)
    #define pb(x) push_back(x)
    using namespace std;
    const int maxn=1e5+7;
    int dmin[maxn][18];
    int dmax[maxn][18];
    int cnt[maxn];
    int pos[maxn],id[maxn];
    bool ans[maxn];
    int n,m,t,sum;
    vector<int>a,b;
    struct node
    {
        int l,r,id;
        bool operator <(const node &a)const
        {
            return pos[l]==pos[a.l]?r<a.r:pos[l]<pos[a.l];
        }
    } q[maxn];
    int getid(int x)
    {
        return lower_bound(a.begin(),a.end(),x)-a.begin()+1;
    }
    int rmq(int l,int r)
    {
        int k=log2(r-l+1);
        int minn= min(dmin[l][k],dmin[r-(1<<k)+1][k]);
        int maxx= max(dmax[l][k],dmax[r-(1<<k)+1][k]);
        return maxx-minn+1;
    }
    void add(int x)
    {
        if(cnt[id[x]]==0)sum++;
        cnt[id[x]]++;
    }
    void del(int x)
    {
        cnt[id[x]]--;
        if(cnt[id[x]]==0)sum--;
    }
    int main()
    {
        scanf("%d",&t);
        while(t--)
        {
            M(cnt,0);
            a.clear();
            b.clear();
            scanf("%d%d",&n,&m);
            int sz=sqrt(n);
            for(int i=1; i<=n; i++)
            {
                scanf("%d",&dmax[i][0]);
                dmin[i][0]=dmax[i][0];
                a.pb(dmax[i][0]);
                pos[i]=i/sz;
            }
            b=a;
            sort(a.begin(),a.end());
            a.erase(unique(a.begin(),a.end()),a.end());
            for(int i=1;i<=n;i++)id[i]=getid(b[i-1]);
            for(int j=1; (1<<j)<n; j++)
                for(int i=1; i+(1<<j)-1<=n; i++)
                {
                    dmin[i][j]=min(dmin[i][j-1],dmin[i+(1<<(j-1))][j-1]);
                    dmax[i][j]=max(dmax[i][j-1],dmax[i+(1<<(j-1))][j-1]);
                }
            for(int i=1; i<=m; i++) scanf("%d%d",&q[i].l,&q[i].r),q[i].id=i;
            sort(q+1,q+1+m);
            int L=1,R=0;
            sum=0;
            for(int i=1;i<=m;i++)
            {
                while(L<q[i].l) del(L++);
                while(L>q[i].l) add(--L);
                while(R<q[i].r) add(++R);
                while(R>q[i].r) del(R--);
                ans[q[i].id]= rmq(q[i].l,q[i].r)==sum?true:false;
            }
            for(int i=1;i<=m;i++)printf("%s
    ",ans[i]?"YES":"NO");
        }
    }
    
    
  • 相关阅读:
    python3调用js的库之execjs
    字体替换 re.sub
    asyncio和aiohttp
    微信公众号数据抓取
    celery
    Airtest 的连接安卓模拟器
    Scrapy同时启动多个爬虫
    随机IP代理插件Scrapy-Proxies
    Charles和mitmproxy代理设置
    win下删除EFI分区
  • 原文地址:https://www.cnblogs.com/kuronekonano/p/11135700.html
Copyright © 2011-2022 走看看