2018黑龍江省賽D A Sequence Game(莫隊+ST表維護最值)
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.
來源/分類
【題意】
給出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;
}