1. 程式人生 > >黑龍江省賽 A Sequence Game(離散化+莫隊演算法+ST表 RMQ)

黑龍江省賽 A Sequence Game(離散化+莫隊演算法+ST表 RMQ)

問題 D: A Sequence Game

時間限制: 1 Sec  記憶體限制: 128 MB
提交: 148  解決: 42
[提交] [狀態] [討論版] [命題人:admin]

題目描述

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的序列,有m次詢問,每次問詢一個區間中是否區間中最大的數到最小的數都出現了至少一次

題解:明顯可以用莫隊演算法對於區間查詢進行排序然後分塊處理,每次查詢區間的最大值和最小值然後莫隊處理區間中不同的數字的個數,若最大值減去最小值+1<=區間中不同數字的個數,則輸出YES否則輸出NO,區間RMQ可以用ST表進行優化,複雜度O(n*sqrt(n)),一開始我用map標記區間中出現的數字的個數總是執行錯誤,將資料離散化再用陣列標記就可以了;

#include<bits/stdc++.h>
#define rep(i,s,t) for(int i=s;i<=t;i++)
#define SI(i) scanf("%lld",&i)
#define PI(i) printf("%lld\n",i)
using namespace std;
typedef long long ll;
const int mod=1e9+7;
const int MAX=2e5+5;
const int INF=0x3f3f3f3f;
const double eps=1e-8;
int dir[9][2]={0,1,0,-1,1,0,-1,0, -1,-1,-1,1,1,-1,1,1};
template<class T>bool gmax(T &a,T b){return a<b?a=b,1:0;}
template<class T>bool gmin(T &a,T b){return a>b?a=b,1:0;}
template<class T>void gmod(T &a,T b){a=((a+b)%mod+mod)%mod;}
typedef pair<ll,ll> PII;

ll n,cnt,st[MAX][25][2],powll[50],lg[MAX],ans[MAX],vis[MAX],a[MAX],b[MAX];

int del(ll x)
{
    x=st[x][0][0];
    if(vis[x]==1) cnt--;
    vis[x]--;
}

int add(ll x)
{
    x=st[x][0][0];
    if(vis[x]==0) cnt++;
    vis[x]++;
}

struct node
{
    ll l,r,id;
}p[MAX];

int block;
int cmp(node a,node b)
{
    if(!block) block++;
    if( (a.l/block) == (b.l/block) )
        return a.r<b.r;
    return a.l<b.l;
}

int main()
{
    powll[0]=1;
    for(int i=1;i<=25;i++)
        powll[i]=(powll[i-1]<<1);
    lg[0]=-1;
    int T;
    scanf("%d",&T);
    while(T--)
    {
        memset(vis,0,sizeof(vis));
        ll m;
        scanf("%lld%lld",&n,&m);

        block=(int)(sqrt(n*1.0)+0.5);
        for(int i=1;i<=n;i++)
            scanf("%lld",&a[i]),lg[i]=lg[i>>1]+1,b[i]=a[i];

        sort(b+1,b+1+n);
        for(int i=1;i<=n;i++)
        {
            st[i][0][0]=lower_bound(b+1,b+1+n,a[i])-b-1;
            st[i][0][1]=st[i][0][0];
        }

        for(int j=1;(1<<j)<=n;j++)
            for(int i=1;i<=n;i++)
            {
                st[i][j][0]=max(st[i][j-1][0],st[i+(1<<j-1)][j-1][0]);
                st[i][j][1]=min(st[i][j-1][1],st[i+(1<<j-1)][j-1][1]);
            }

        for(int i=1;i<=m;i++)
        {
            scanf("%lld%lld",&p[i].l,&p[i].r);
            p[i].id=i;
        }

        sort(p+1,p+1+m,cmp);

        ll L=1,R=0;cnt=0;

        for(int i=1;i<=m;i++)
        {
            ll l=p[i].l;
            ll r=p[i].r;
            while(L<l) del(L++);
            while(L>l) add(--L);
            while(R>r) del(R--);
            while(R<r) add(++R);
            ll d=lg[r-l+1];
            r=r-powll[d]+1;

            ll a=min(st[l][d][1],st[r][d][1]);
            ll b=max(st[l][d][0],st[r][d][0]);

            if(cnt>=b-a+1)
                ans[p[i].id]=1;
            else
                ans[p[i].id]=0;
        }

        for(int i=1;i<=m;i++)
            if(ans[i])
                printf("YES\n");
            else
                printf("NO\n");
    }
    return 0;
}