2018黑龙江省赛D A Sequence Game(莫队+ST表维护最值)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/winter2121/article/details/82425443

7218: A Sequence Game

时间限制: 1 Sec  内存限制: 128 MB
提交: 160  解决: 46
[提交] [状态] [讨论版] [命题人: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.

来源/分类

2018黑龙江省赛 

[提交] [状态]

【题意】

给出n个数字,m次询问。每次询问区间[L,R]之间的所有数字,是否能从最小值到最大值连续起来,例如4,1,3,2就是从1到4连续的。是则输出YES,否则NO

【分析】

因为不涉及修改操作,直接ST表维护区间最大值和最小值即可。莫队可以维护区间种数。当区间内种数==区间最大值-区间最小值+1时,即为YES,否则NO;

卡超时卡到秃顶,原因在于莫队更新时,询问离散化数组用lower_bound增加了logn的复杂度,其实这个可以在莫队之前就预处理。时间复杂度O(n*sqrt(n))

【代码】

#include<bits/stdc++.h>
using namespace std;
const int MAX=1e5+5;
const int INF=0x3f3f3f3f;

int n,m,a[MAX];
/******倍增最值*******/
int Max[MAX][20],Min[MAX][20];
void myinit()
{
    int ok=log2(n+0.5)+1;
    for(int i=0;i<ok;i++)
    {
        for(int j=1;j+(1<<i)-1<=n;j++)
        {
            Max[j][i]=-INF;
            Min[j][i]=INF;
            if(i==0)Max[j][i]=Min[j][i]=a[j];
            else
            {
                Max[j][i]=max(Max[j][i-1],Max[j+(1<<(i-1))][i-1]);
                Min[j][i]=min(Min[j][i-1],Min[j+(1<<(i-1))][i-1]);
            }
        }
    }
}
int Qmax(int l,int r)
{
    int len=log2(r-l+1.5)+1;
    while((1<<len)>r-l+1)len--;
    return max(Max[l][len],Max[r-(1<<len)+1][len]);
}
int Qmin(int l,int r)
{
    int len=log2(r-l+1.5)+1;
    while((1<<len)>r-l+1)len--;
    return min(Min[l][len],Min[r-(1<<len)+1][len]);
}

/*********莫队分块********/
struct query{
    int L,R,id,ans;
}Q[MAX];
int block; //块
bool cmpblock(query a,query b)
{
    if(a.L/block==b.L/block)return a.R<b.R;
    return a.L/block<b.L/block;
}
bool cmpid(query a,query b)
{
    return a.id<b.id;
}
int each[MAX]; //每个数出现的次数;
void update(int &sum,int x,int change)
{
    int rk=a[x];
    each[rk]+=change;
    if(each[rk]==0&&change==-1 || each[rk]==1&&change==1)
        sum+=change;
}
int ha[MAX];
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&m);
        int top=0;
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
            ha[++top]=a[i];
        }
        myinit();
        sort(ha+1,ha+1+top);
        top=unique(ha+1,ha+1+top)-ha-1;
        for(int i=1;i<=n;i++)a[i]=lower_bound(ha+1,ha+1+top,a[i])-ha;
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d",&Q[i].L,&Q[i].R);
            Q[i].id=i;
        }
        block=pow(n,0.57);
        sort(Q+1,Q+1+m,cmpblock);
        for(int i=0;i<=top;i++)each[i]=0;
        int l=1,r=0,sum=0;
        for(int i=1;i<=m;i++)
        {
            int L=Q[i].L, R=Q[i].R;
            for(;l<L;l++) update(sum,l,-1);
            for(;l>L;l--)update(sum,l-1,1);
            for(;r>R;r--) update(sum,r,-1);
            for(;r<R;r++)update(sum,r+1,1);
            Q[i].ans=(sum==Qmax(l,r)-Qmin(l,r)+1);
        }
        sort(Q+1,Q+1+m,cmpid);
        for(int i=1;i<=m;i++)
        {
            if(Q[i].ans==1)printf("YES\n");
            else printf("NO\n");
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/winter2121/article/details/82425443