hdoj6483 A Sequence Game(ST预处理RMQ+莫队)

传送:http://acm.hdu.edu.cn/showproblem.php?pid=6483

题意:有长度为$n$的数组,对于一个子区间$[l,r]$内,存在最大值$mx$与最小值$mi$,有$q$的询问,每个询问要求判断在某个子区间$[l,r]$内$[mi,mx]$的值是否连续存在,即$mi,mi+1,....,mx$每个数都出现过至少一次。$T=5,1<=n<=10000,1<=a_i<=10^9,1<=m<=100000$

分析:

多个区间查询问题,考虑莫队算法。

对于每一个询问,需要判断$mi$到$mx$内的数是否全部存在,且需要知道$mi$与$mx$。考虑先预处理出每个子区间的最值,离线查询。

$a_i<=10^9$,数组$num[]$没办法开下,需要离散化处理。

先ST预处理最值,然后离散化,莫队求区间内值种类的个数。

代码:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int maxn=1e5+10;
 4 struct node{
 5     int l,r,id,block,mx,mi;
 6 }q[maxn];
 7 int a[maxn],b[maxn],maxPoint[maxn][30],minPoint[maxn][30],num[maxn];
 8 bool ans[maxn];
 9 int cnt=0,n,m,block,ll,rr;
10 bool cmp(node p,node q){
11     return p.block<q.block || p.block==q.block && p.r<q.r;
12 }
13 void add(int x){
14     int tmp=a[x];
15     if (num[tmp]==0) cnt++;
16     num[tmp]++;
17 }
18 void del(int x){
19     int tmp=a[x];
20     if (num[tmp]==1) cnt--;
21     num[tmp]--;
22 }
23 void init(){
24     for (int i = 1; i <= n; i++){
25         minPoint[i][0] = maxPoint[i][0] = a[i];
26     }
27     for (int j = 1; (1 << j) <= n; j++){
28         for (int i = 1; i + (1 << j) - 1 <= n; i++){
29             int p = (1 << (j - 1));
30             minPoint[i][j] = min(minPoint[i][j - 1], minPoint[i + p][j - 1]);
31             maxPoint[i][j] = max(maxPoint[i][j - 1], maxPoint[i + p][j - 1]);
32         }
33     }
34 }
35 int queryMin(int l, int r){
36     int k = log2((double)(r - l + 1));
37     return min(minPoint[l][k], minPoint[r - (1 << k) + 1][k]);
38 }
39 
40 int queryMax(int l, int r){
41     int k = log2((double)(r - l + 1));
42     return max(maxPoint[l][k], maxPoint[r - (1 << k) + 1][k]);
43 }
44 bool calc(node tmp){
45     if (tmp.mx-tmp.mi+1==cnt) return true;
46     return false;
47 }
48 void init2(){
49     sort(b+1,b+1+n);
50     int tmp=unique(b+1,b+1+n)-(b+1);
51     for (int i=1;i<=n;i++){
52         a[i]=lower_bound(b+1,b+1+tmp,a[i])-b;
53         num[i]=0;
54     }
55 } 
56 int main(){
57     int t; scanf("%d",&t);
58     while (t--){
59         scanf("%d%d",&n,&m);
60         for (int i=1;i<=n;i++){
61             scanf("%d",&a[i]);
62             b[i]=a[i];
63         }
64         init();
65         //离散化
66         block=sqrt(n);
67         for (int i=0;i<m;i++){
68             scanf("%d%d",&q[i].l,&q[i].r);
69             q[i].id=i; q[i].block=q[i].l/block;
70             q[i].mx=queryMax(q[i].l,q[i].r);
71             q[i].mi=queryMin(q[i].l,q[i].r);
72         }
73         init2();
74         sort(q,q+m,cmp);
75         ll=1,rr=0; cnt=0;
76         for (int i=0;i<m;i++){
77             while (ll<q[i].l) del(ll++);
78             while (ll>q[i].l) add(--ll);
79             while (rr<q[i].r) add(++rr);
80             while (rr>q[i].r) del(rr--); 
81             ans[q[i].id]=calc(q[i]);
82         }
83         for (int i=0;i<m;i++)
84             if (ans[i]) printf("YES\n");
85             else printf("NO\n");
86     }
87     return 0;
88 } 
hdoj6483

 

转载于:https://www.cnblogs.com/changer-qyz/p/10719824.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值