HDU - 6483 A Sequence Game —— 线段树+莫队+读入挂

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.
Input
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 positive integers A1,A2,…,An.
Then there will be m lines followed. Each line contains to positive numbers Li,Ri indicating that the ith query’s interval is [Li,Ri].
Output
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.
Sample Input
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
Sample Output
YES
YES
NO
NO
YES
YES

Hint
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.

题意:

给你一个数组,每次询问你l到r的区间中是否从这个区间的最小值到这个区间的最大值都出现过,是输出YES,否则输出NO:1 2 3 3 就是YES 1 2 2 4就是NO。

题解:

那么这道题就变成了区间不同值的个数>=区间最大值-区间最小值+1。
求区间不同值的个数的时候一开始想用主席树来着,但是它给的空间范围太小了,所以只能以时间换空间,用莫队来做。注意这里不能用unordered_map,因为就算它的时间复杂度也太大了,所以得离散化做。区间查询可以用线段树。

#include<bits/stdc++.h>
using namespace std;

namespace fastIO {
    #define BUF_SIZE 100000
    //fread -> read
    bool IOerror = 0;
    inline char nc() {
        static char buf[BUF_SIZE], *p1 = buf + BUF_SIZE, *pend = buf + BUF_SIZE;
        if(p1 == pend) {
            p1 = buf;
            pend = buf + fread(buf, 1, BUF_SIZE, stdin);
            if(pend == p1) {
                IOerror = 1;
                return -1;
            }
        }
        return *p1++;
    }
    inline bool blank(char ch) {
        return ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t';
    }
    inline void read(int &x) {
        char ch;
        while(blank(ch = nc()));
        if(IOerror) return;
        for(x = ch - '0'; (ch = nc()) >= '0' && ch <= '9'; x = x * 10 + ch - '0');
    }
    #undef BUF_SIZE
};
using namespace fastIO;

const int N=1e5+5;
struct node
{
    int l,r,id;
}q[N];
int pos[N];
bool cmp(node a,node b)
{
    return pos[a.l]<pos[b.l]||pos[a.l]==pos[b.l]&&a.r<b.r;
}
int a[N];
int maxn[N*4],minn[N*4];
void build(int l,int r,int root)
{
    if(l==r)
    {
        maxn[root]=minn[root]=a[l];
        return ;
    }
    int mid=l+r>>1;
    build(l,mid,root<<1);
    build(mid+1,r,root<<1|1);
    maxn[root]=max(maxn[root<<1],maxn[root<<1|1]);
    minn[root]=min(minn[root<<1],minn[root<<1|1]);
}
int qmax(int l,int r,int root,int ql,int qr)
{
    if(l>=ql&&r<=qr)
        return maxn[root];
    int mid=l+r>>1;
    int mx=0;
    if(mid>=ql)
        mx=qmax(l,mid,root<<1,ql,qr);
    if(mid<qr)
        mx=max(mx,qmax(mid+1,r,root<<1|1,ql,qr));
    return mx;
}
int qmin(int l,int r,int root,int ql,int qr)
{
    if(l>=ql&&r<=qr)
        return minn[root];
    int mid=l+r>>1;
    int mn=1e9;
    if(mid>=ql)
        mn=qmin(l,mid,root<<1,ql,qr);
    if(mid<qr)
        mn=min(mn,qmin(mid+1,r,root<<1|1,ql,qr));
    return mn;
}
int vis[N],b[N];
int num;
int ans[N];
void add(int pos)
{
    if(!vis[a[pos]])
        num++;
    vis[a[pos]]++;
}
void del(int pos)
{
    if(vis[a[pos]]==1)
        num--;
    vis[a[pos]]--;
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        memset(vis,0,sizeof(vis));
        int n,qq;
        read(n),read(qq);
        int blog=sqrt(n);
        for(int i=1;i<=n;i++)
            pos[i]=(i-1)/blog+1;
        for(int i=1;i<=n;i++)
            read(a[i]),b[i]=a[i];
        sort(b+1,b+1+n);
        for(int i=1;i<=n;i++)
            a[i]=lower_bound(b+1,b+1+n,a[i])-b;
        build(1,n,1);
        for(int i=1;i<=qq;i++)
            read(q[i].l),read(q[i].r),q[i].id=i;
        sort(q+1,q+1+qq,cmp);
        num=0;
        int l=q[1].l,r=q[1].l-1;
        for(int i=1;i<=qq;i++)
        {
            while(r<q[i].r)
                add(++r);
            while(l>q[i].l)
                add(--l);
            while(l<q[i].l)
                del(l++);
            while(r>q[i].r)
                del(r--);
            int mx=qmax(1,n,1,q[i].l,q[i].r);
            int mn=qmin(1,n,1,q[i].l,q[i].r);
            if(mx-mn+1>num)
                ans[q[i].id]=0;
            else
                ans[q[i].id]=1;
        }
        for(int i=1;i<=qq;i++)
            printf("%s\n",ans[i]?"YES":"NO");
        for(int i=0;i<n*4;i++)
            maxn[i]=0,minn[i]=1e9;
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值