2018 ccpc黑龙江省赛 D.A Sequence Game (莫队)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6483

题目大意:

      n个数,m次询问,问是否L到R中最小值到最大值之间是否全部的数都出现过。

只要统计区间不同数字的个数是否等于max-min+1就可以了,不过需要离散化。莫队裸题。

不知道为什么用莫队奇偶优化过不去,普通的莫队就可以过。

辣鸡小编勘误:在鑫爹的英明指导下,发现自己懂了奇偶优化之后太激动了,瞎捷豹打奇偶优化少打个return,该打,该打。

奇偶优化牛逼,鑫爹牛逼。奇偶优化大概省了100ms。

代码:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int MAXN=1e5+5;
int b[MAXN],a[MAXN];
int n,m,ans[MAXN],C[MAXN],unit;
int mm[MAXN], f[MAXN][20][2];

void st_prework()
{
    for(int i = 1; i <= n; i ++) f[i][0][0] = f[i][0][1] = a[i];
    int t = log(n) / log(2) + 1;
    for(int j = 1; j < t; j ++){
        for(int i = 1; i <= n - (1 << j) + 1; i ++){
            f[i][j][0] = min(f[i][j - 1][0], f[i + (1 << (j - 1))][j - 1][0]);
            f[i][j][1] = max(f[i][j - 1][1], f[i + (1 << (j - 1))][j - 1][1]);
        }
    }
}

int fmin(int l, int r)
{
    int k = log(r - l + 1)/log(2);
    return min(f[l][k][0], f[r - (1 << k) + 1][k][0]);
}

int fmax(int l, int r)
{
    int k = log(r - l + 1)/log(2);
    return max(f[l][k][1], f[r - (1 << k) + 1][k][1]);
}

inline bool scan_d(int &num)
{
        char in;bool IsN=false;
        in=getchar();
        if(in==EOF) return false;
        while(in!='-'&&(in<'0'||in>'9')) in=getchar();
        if(in=='-'){ IsN=true;num=0;}
        else num=in-'0';
        while(in=getchar(),in>='0'&&in<='9'){
                num*=10,num+=in-'0';
        }
        if(IsN) num=-num;
        return true;
}
struct Query
{
    int L,R,id;
    int Max,Min;
}node[MAXN];
int k;
int aa(int x)
{
    return lower_bound(a+1,a+1+k,x)-a;
}
bool cmp(Query a,Query b)
{
    if(a.L/unit!=b.L/unit)return a.L<b.L;
    if((a.L/unit)&1) return a.R>b.R;
    else return a.R<b.R;
}
void work()
{
    int temp=0;
    int L=1,R=0;
    for(int i=1;i<=m;i++){
        while(R<node[i].R){
            R++;
            if(mm[C[R]]==0)temp++;
            mm[C[R]]++;
        }
        while(R>node[i].R){
            if(mm[C[R]]==1)temp--;
            mm[C[R]]--;
            R--;
        }
        while(L<node[i].L){
            if(mm[C[L]]==1)temp--;
            mm[C[L]]--;
            L++;
        }
        while(L>node[i].L){
            L--;
            if(mm[C[L]]==0)temp++;
            mm[C[L]]++;
        }
        if(temp==node[i].Max-node[i].Min+1)
        ans[node[i].id]=1;
        else ans[node[i].id]=0;
    }
}
int main()
{
    int t;
    scan_d(t);
    while(t--)
    {
        memset(mm,0,sizeof(mm));
        scan_d(n);scan_d(m);
        unit=sqrt(n);
        for(int i=1;i<=n;i++){
            scan_d(C[i]);
            a[i]=C[i];
        }
        st_prework();
        sort(a+1,a+1+n);
        k=unique(a+1,a+1+n)-a-1;
        for(int i=1;i<=n;i++){
            C[i]=lower_bound(a+1,a+1+k,C[i])-a;
        }
        for(int i=1;i<=m;i++){
            scan_d(node[i].L);scan_d(node[i].R);
            node[i].id=i;
            node[i].Max=fmax(node[i].L,node[i].R);
            node[i].Min=fmin(node[i].L,node[i].R);
        }
        sort(node+1,node+1+m,cmp);
        work();
        for(int i=1;i<=m;i++){
            if(ans[i])puts("YES");
            else puts("NO");
        }
    }
}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值