1. 程式人生 > >「BZOJ3339」Rmq Problem(5366)

「BZOJ3339」Rmq Problem(5366)

題目描述

輸入

輸出

樣例輸入

7 5
0 2 1 0 1 3 2
1 3
2 3
1 4
3 6
2 7

提示

 


 

這個題說來也挺有意思的

當時集訓的時候遇到了一道類似的題,但是題意與此不同,我太菜了,理解成了這個題233結果爆零(蒟蒻咆哮:“唉我AC呢!?”)

所以就把以前寫的碼翻了出來,交了上去,果然A了2333

當時的寫法是這樣的:

首先處理出每個數下一次出現的位置,這樣每個數字就處理成了 這段區間內這個數沒有出現過,數量是O(n)級別的

那麼一個詢問區間的答案就是所有套在它外面的不出現區間的最小值

具體實現就是首先離線,將“詢問區間”和“不出現區間”在一起按照左端點排序,如果相同則優先處理“不出現區間”

此時維護一個線段樹,位置表示的是區間的右端點,這個位置上存的是:l小於等於當前掃到的L,且以這個位置為r的區間中數最小的是啥

那麼如果掃到了一個提問,那麼答案就是(R,N)這個區間內最小值

當時寫碼的時候有點蒙圈,實際上好像寫個單點修改就好了?

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #define maxn 200005
 5
#define inf n+1 6 using namespace std; 7 int a[maxn],nxt[maxn],top; 8 int n,m,s[maxn*4],tag[maxn*4]; 9 struct line{ 10 int l,r,x,o; 11 }q[maxn*10]; 12 bool cmp(line A,line B){if(A.l!=B.l)return A.l<B.l;else return A.o<B.o;} 13 int ans[maxn]; 14 void build(int x,int l,int r){ 15 s[x]=tag[x]=inf;
16 if(l==r)return; 17 int mid=(l+r)/2; 18 build(x+x,l,mid); 19 build(x+x+1,mid+1,r); 20 } 21 void pushdown(int x,int l,int r){ 22 if(l==r){ 23 tag[x]=inf; 24 return; 25 } 26 s[x+x]=min(s[x+x],tag[x]); 27 tag[x+x]=min(tag[x+x],tag[x]); 28 s[x+x+1]=min(s[x+x+1],tag[x]); 29 tag[x+x+1]=min(tag[x+x+1],tag[x]); 30 tag[x]=inf; 31 return; 32 } 33 void add(int x,int l,int r,int L,int R,int k){ 34 if(l==L&&r==R){ 35 s[x]=min(s[x],k); 36 tag[x]=min(tag[x],k); 37 return; 38 } 39 pushdown(x,l,r); 40 int mid=(l+r)/2; 41 if(R<=mid)add(x+x,l,mid,L,R,k); 42 else if(L>mid)add(x+x+1,mid+1,r,L,R,k); 43 else add(x+x,l,mid,L,mid,k),add(x+x+1,mid+1,r,mid+1,R,k); 44 s[x]=min(s[x+x],s[x+x+1]); 45 } 46 int query(int x,int l,int r,int L,int R){ 47 if(l==L&&r==R)return s[x]; 48 pushdown(x,l,r); 49 int mid=(l+r)/2; 50 if(R<=mid)return query(x+x,l,mid,L,R); 51 else if(L>mid)return query(x+x+1,mid+1,r,L,R); 52 else return min(query(x+x,l,mid,L,mid),query(x+x+1,mid+1,r,mid+1,R)); 53 } 54 int main(){ 55 scanf("%d%d",&n,&m); 56 build(1,1,n); 57 nxt[0]=n+1; 58 for(int i=1;i<=n;i++){ 59 scanf("%d",&a[i]); 60 nxt[i]=n+1; 61 } 62 nxt[n+1]=n+1; 63 for(int i=n;i>=1;i--){ 64 if(nxt[a[i]]-i-1>0){ 65 q[++top].o=0; 66 q[top].l=i+1; 67 q[top].r=nxt[a[i]]-1; 68 q[top].x=a[i]; 69 } 70 nxt[a[i]]=i; 71 } 72 for(int i=0;i<=n+1;i++) 73 if(nxt[i]-1>0){ 74 q[++top].o=0; 75 q[top].l=1; 76 q[top].r=nxt[i]-1; 77 q[top].x=i; 78 } 79 for(int i=1,l,r;i<=m;i++){ 80 scanf("%d%d",&l,&r); 81 q[++top].o=1; 82 q[top].l=l; 83 q[top].r=r; 84 q[top].x=i; 85 } 86 sort(q+1,q+1+top,cmp); 87 for(int i=1;i<=top;i++){ 88 if(q[i].o==0) 89 add(1,1,n,q[i].r,q[i].r,q[i].x); 90 else{ 91 int A=query(1,1,n,q[i].r,n); 92 ans[q[i].x]=A; 93 } 94 } 95 for(int i=1;i<=m;i++)printf("%d\n",ans[i]); 96 return 0; 97 }
View Code

 

不過這個題還有線上的主席樹做法,等我補全~