區間MEX 線段樹維護mex陣列
NKOJ 4254 區間MEX
問題描述
給你一個長度為n的數列,元素編號1到n,第i個元素值為Ai。現在有m個形如(L,R)的提問,你需要回答出區間[L,R]的mex值。即求出區間[L,R]中沒有出現過的最小的非負整數。
輸入格式
第一行,兩個整數n和m
第二行,n個空格間隔的整數,表示數列A
接下來m行,每行兩個整數L,R,表示一次詢問
輸出格式
m行,每行一個整數,表示對應詢問的答案。
樣例輸入
7 5
0 2 1 0 1 3 2
1 3
2 3
1 4
3 6
2 7
樣例輸出
3
0
3
2
4
資料範圍
1<=n,m<=200000
0<=Ai<=200000
1<=L<=R<=n
分析:
由於沒有修改操作,可以考慮離線演算法。
首先考慮暴力的做法。對於固定的左端點,如何用
然而本題的左端點是任意的。但是根據離線演算法的基本操作,我們可以把討論有序化。不妨將詢問按左端點從小到大排序。現在假設我們已經求出了以i為左端點的所有區間的mex值,想要得到以i+1為左端點的所有區間的mex值,考慮兩種狀態如何轉移。
從i到i+1,只有一個不同:那就是有些區間裡本來有
這些區間會受到怎樣的影響?考慮
最後總結一下做法:
1預處理:
(1)用
(2)預處理出每個數下一次出現的位置;
(3)按區間左端點將詢問排序;
2.從1到n由小到大討論。處理完以i為左端點的詢問後,對
程式碼:
#include<stdio.h>
#include<algorithm>
#include<cstring>
#define MAXM 200005
#define MAXN 200005
#define MAXT 800005
using namespace std;
int N,M,A[MAXN],mex[MAXN],Ans[MAXM],nex[MAXN],las[MAXN];
bool mark[MAXN];
struct node{int l,r,id;}qry[MAXM];
bool operator<(node x,node y)
{
return x.l<y.l;
}
int tot,lazy[MAXT],ls[MAXT],rs[MAXT],a[MAXT],b[MAXT],v[MAXT];
//lazy等於-1,說明沒有需要下放的操作
void Putdown(int p)
{
int Ls=ls[p],Rs=rs[p];
if(~lazy[Ls])lazy[Ls]=min(lazy[p],lazy[Ls]);
else lazy[Ls]=lazy[p];
if(~lazy[Rs])lazy[Rs]=min(lazy[p],lazy[Rs]);
else lazy[Rs]=lazy[p];
v[Ls]=min(v[Ls],lazy[p]);
v[Rs]=min(v[Rs],lazy[p]);
lazy[p]=-1;
}
int Build(int x,int y)
{
tot++;
int mid=x+y>>1,p=tot;
a[p]=x;b[p]=y;
if(x==y)
{
v[p]=mex[x];
return p;
}
ls[p]=Build(x,mid);
rs[p]=Build(mid+1,y);
v[p]=min(v[ls[p]],v[rs[p]]);
return p;
}
void Modify(int p,int l,int r,int k)
{
if(b[p]<l||a[p]>r)return;
if(~lazy[p])Putdown(p);
if(a[p]>=l&&b[p]<=r)
{
lazy[p]=k;
v[p]=min(v[p],k);
return;
}
int mid=a[p]+b[p]>>1;
Modify(ls[p],l,r,k);
Modify(rs[p],l,r,k);
}
int GetAns(int p,int k)
{
if(~lazy[p])Putdown(p);
if(a[p]==b[p]&&a[p]==k)return v[p];
int mid=a[p]+b[p]>>1;
if(k<=mid)return GetAns(ls[p],k);
return GetAns(rs[p],k);
}
int main()
{
int i,j=0;
scanf("%d%d",&N,&M);
for(i=1;i<=N;i++)scanf("%d",&A[i]);
for(i=N;i;i--)
{
if(las[A[i]]==0)nex[i]=N+1;
else nex[i]=las[A[i]];
las[A[i]]=i;
}
for(i=1;i<=M;i++)scanf("%d%d",&qry[i].l,&qry[i].r),qry[i].id=i;
for(i=1;i<=N;i++)
{
mark[A[i]]=true;
for(;;j++)if(!mark[j])break;
mex[i]=j;
}
sort(qry+1,qry+M+1);
memset(lazy,-1,sizeof(lazy));
Build(1,N);
for(i=1,j=1;i<=N&&j<=M;i++)
{
while(qry[j].l==i)
{
Ans[qry[j].id]=GetAns(1,qry[j].r);
j++;
}
Modify(1,1,nex[i]-1,A[i]);
}
for(i=1;i<=M;i++)printf("%d\n",Ans[i]);
}
相關推薦
區間MEX 線段樹維護mex陣列
NKOJ 4254 區間MEX 問題描述 給你一個長度為n的數列,元素編號1到n,第i個元素值為Ai。現在有m個形如(L,R)的提問,你需要回答出區間[L,R]的mex值。即求出區間[L,R]中沒有出現過的最小的非負整數。 輸入格式 第一行
[Noi2016]區間[離散化+線段樹維護+決策單調性]
fin include efi cmp http 說明 int min unique 4653: [Noi2016]區間 Time Limit: 60 Sec Memory Limit: 256 MBSubmit: 621 Solved: 329[Submit][
BZOJ.3585.mex(線段樹)
min href turn har www tdi markdown opera 區間 題目鏈接 考慮\([1,i]\)的\(mex[i]\),顯然是單調的 而對於\([l,r]\)與\([l+1,r]\),如果\(nxt[a[l]]>r\),那麽\([l+1,r]\
FJUT3568 中二病也要敲程式碼(線段樹維護區間連續最值)題解
題意:有一個環,有1~N編號,m次操作,將a位置的值改為b,問你這個環當前最小連續和多少(不能全取也不能不取) 思路:用線段樹維護一個區間最值連續和。我們設出兩個變數Lmin,Rmin,Mmin表示區間左邊最小連續和,右邊最小連續和,區間最小連續和,顯然這可以通過這個方式更新維護。 現在我們已經可以維
jsk Star War (線段樹維護區間最小最大值 + 二分)
Description 公元20XX年,人類與外星人之間的大戰終於爆發。 現有一個人類軍團,由n名士兵組成,第i個士兵的戰鬥力值對應一個非負整數ai (1 \leq i \leq n1≤i≤n)。 有一天,某個戰力爆表的外星人NaN單獨向地球人宣戰,已知它的戰力值為k (1 \leq
最敏捷的機器人(線段樹維護區間最值)
題面: Wind設計了很多機器人。但是它們都認為自己是最強的,於是,一場比賽開始了……機器人們都想知道誰是最敏捷的,於是它們進行了如下一個比賽。首先,他們面前會有一排共n個數,它們比賽看誰能最先把每連續k個數中最大和最小值寫下來,當然,這些機器人運算速度都很,它們比賽的是誰寫得快。但是Wind也想知道答案,
線段樹維護區間(平方和,立方和)修改區間(加,賦值,乘)
題目地址 /* * @Author: hannibal * @Date: 2018-08-07 10:42:26 * @Last Modified by: hannibal * @Last Modified time: 2018-08-07 17:08:
牛課練習賽34 Flittle w and Discretization 主席樹維護Mex
ittle w and Discretization 主席樹維護Mex。 每個右端點 r 維護出一棵 在[1, r ] 區間中 其他所有的 值離這個 r 最近的的位置是多少。 然後詢問區間[L,R]的時候,從rt[R] 出發,然後如果左兒子的中所有出線位置的最小值 >= L, 則說明他們所有的點都
Fast Arrangement (線段樹 維護區間最大值 lazy標記)
Fast Arrangement 題意: 有一列火車同一時刻只能承載K個人,然後有Q個人要買票(給出Q組區間表示要買票的區間),(注意: 火車行駛區間為a-b的範圍),問那個人可以成功買到票(先到先得)
HDU 5726 GCD (線段樹維護區間gcd)
GCD Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others) Total Submi
線段樹維護區間最大連續和
在我的理解中,線段樹就是線段組成的樹,越靠近根部的層,線段的長度越長,一個結構體(樹的每一個點的左邊界,右邊界以及要維護的值)和三個函式(build——拆的過程),update(更新的過程,更新的時候要先二分找到最底層的區間,然後需要向上將所有的區間都更新了),
hdu1540(線段樹維護連續區間模型)
/* translation: 打地道戰,n個村莊用地道連成一條直線,鬼子有時破壞掉一個村莊,這時八路軍要修好這個據點。現在要求詢問任意一個村莊, 得出這個村莊現在與幾個村莊相連,包括它本身。 solution: 線段樹維護連續子區間 將村莊抽象成一個點,正常下值為
P4198 樓房重建 (線段樹維護區間上升子序列)
題目描述 小A的樓房外有一大片施工工地,工地上有N棟待建的樓房。每天,這片工地上的房子拆了又建、建了又拆。他經常無聊地看著窗外發呆,數自己能夠看到多少棟房子。 為了簡化問題,我們考慮這些事件發生在一個二維平面上。小A在平面上(0,0)點的位置,第i棟樓房可以用一條連線
[永不止步-2017]_區間第K大-線段樹維護
把線段樹的結點的資料域設定為vector型別即可別的操作為區間更新模板 思路就是這樣runtime error暫時沒改對 #include<bits/stdc++.h> using namespace std; #define inf 0x3f3f3f
[UOJ #222][NOI2016]區間(線段樹)
ont 線段樹 div 最短 ans oid tro lib read Description 在數軸上有 n個閉區間 [l1,r1],[l2,r2],...,[ln,rn]。現在要從中選出 m 個區間,使得這 m個區間共同包含至少一個位置。換句話說,就是使得存在一個 x
Codeforces Round #426 (Div. 2) D. The Bakery(線段樹維護dp)
src lap codeforce blank com date close scanf logs 題目鏈接: Codeforces Round #426 (Div. 2) D. The Bakery 題意: 給你n個數,劃分為k段,每段的價值為這一段不同的數的個數,問如何
bzoj 1798 雙標記區間修改線段樹
scrip namespace c++ define sample -c bit 變化 sea 1 #include<bits/stdc++.h> 2 using namespace std; 3 #define MAXN 100000 4 #defi
WHYZOJ-#53 線段樹區間修改(線段樹)
namespace 標記 upd build out state long 輸入 std 【題目描述】: 如題,已知一個數列,你需要進行下面兩種操作: 1.將某區間每一個數加上x 2.求出某區間每一個數的和 【輸入描述】: 第一行包含兩個整數N、M,分別表示該數列數字
hihoCoder 1078 區間查詢線段樹
模板 代碼 maintain 可能 mes () std 測試數據 int 題面: 對於小Ho表現出的對線段樹的理解,小Hi表示挺滿意的,但是滿意就夠了麽?於是小Hi將問題改了改,又出給了小Ho: 假設貨架上從左到右擺放了N種商品,並且依次標號為1到N,其中標號為i的商品的
HDU 6155 Subsequence Count 線段樹維護矩陣
input ans ons tom thml other family 卡常 子序列 Subsequence Count Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 256000/256000 K (J