在賣禮物的超市中有n個櫃子,每個櫃子裡都擺放了乙個禮物,每個禮物有自己的乙個編號,第i個櫃子裡的禮物編號為ai。
茶山牛想給牛牛和牛妹買相同編號的禮物,但禮物有可能在某個時刻被其他人買走,而且櫃子數量太多,因此茶山牛在某個時刻只想知道某乙個櫃子區間是否能買到兩件相同編號的禮物。
具體來說,有q次操作,格式如下:
1 x,第x個櫃子裡的禮物被買走,保證此時這個櫃子裡的禮物還在。
2 l r,茶山牛詢問第l到第r個櫃子未被買走的禮物中是否有兩個禮物編號相同。
對每次茶山牛的詢問輸出一行乙個整數,如果在指定的區間內有兩個禮物編號相同則輸出1,否則輸出0示例1
複製
5 5複製1 2 1 2 1
2 2 4
2 2 5
1 22 2 4
2 2 5
1101
第一次詢問的時候可以買到兩件編號為2的禮物。第三次詢問的時候由於第二件禮物被買走,所以2到4櫃子裡只有一件編號為1的禮物和一件編號為2的禮物。第四次詢問的時候可以買到兩件編號為1的禮物。
這個題就是用線段樹維護陣列nextt[i](這個陣列的含義是後面第乙個出現a[i]的下標),這樣維護
到時候只需要查詢一下[l,r]中的最小值看看是不是小於等於r
pre[i]=book[a[i]];//修改和查詢都是板子上一次出現的下標
nextt[book[a[i]]]=i;
book[a[i]]=i;
//這裡book[i]是暫時儲存a[i]的
再乙個主要的是這裡如果修改了這個x,x的pre和nextt都要修改
還有線段樹要修改兩次:
1.x的後繼變成inf,
2.pre[x]的後繼變成nextt[pre[x]]
change(1,x,inf);//維護的是後繼的下標
nextt[pre[x]]=nextt[x];
if(nextt[x]!=inf)
change(
1,pre[x],nextt[pre[x]]);//
維護的後繼的下標,就是他前乙個的後繼要改
#include#include給你乙個長為n的序列a,有q次詢問。每次詢問給出乙個區間[l,r],詢問al與ar之間是否存在兩個相等的數。#include
using
namespace
std;
typedef
long
long
ll;const ll maxn=5e6+9
;ll over=maxn*4
;ll inf=0x3f3f3f3f3f3f3f3f
;struct
nodet[maxn];
ll book[maxn],a[maxn],pre[maxn],nextt[maxn];
intn,q;
void
push_up(ll p)
void
build(ll p,ll l,ll r)
int mid=(l+r)/2
; build(
2*p,l,mid);
build(
2*p+1,mid+1
,r);
t[p].mi=min(t[2*p].mi,t[2*p+1
].mi);
} void
change(ll p,ll x,ll z)
int mid=(t[p].l+t[p].r)/2
;
if(x<=mid)
else
push_up(p);
}ll query(ll p,ll l,ll r)
int mid=(t[p].l+t[p].r)/2
; ll ans=inf;
if(l<=mid)
if(r>mid)
return
ans;
} int
main()
//for(int i=1;i<=n;i++)
//cout/
for(int i=1;i<=n;i++)
//cout/
for(int i=1;i<=n;i++)
//cout
,n);
while(q--)
change(
1,pre[x],nextt[pre[x]]);//
維護的後繼的下標,就是他前乙個的後繼要改
}
else
else}}
}
共q+2行。
第一行,兩個整數n,q。
第二行,n個整數a1,a2……an。
接下來q行,每行兩個整數l,r。
對每個詢問輸出一行,yes或no.
樣例輸入 copy
4 2樣例輸出 copy1 2 3 2
1 32 4
no提示對於30%的資料,n,q≤1000,ai≤1000。yes
對於60%的資料,n,q≤10000。
對於100%的資料,1≤ai≤106,1≤n,q≤105,1≤l≤r≤n,資料有梯度。
#pragma gcc optimize(1)#pragma gcc optimize(2)
#pragma gcc optimize(3,"ofast","inline")#include
#include
#include
using
namespace
std;
typedef
long
long
ll;const
int maxn=3e6+9
;int
a[maxn];
intne[maxn];
intpre[maxn];
intbook[maxn];
struct
nodet[maxn];
void push(int
p)void build(int p,int l,int
r)
int mid=(l+r)/2
; build(
2*p,l,mid);
build(
2*p+1,mid+1
,r);
push(p);
}int query(int p,int l,int
r)
if(r<=t[2*p].r)
else
if(l>=t[2*p+1
].l)
else
}int
main()
memset(ne,
0x3f,sizeof
(ne));
memset(book,-1,sizeof
(book));
for(int i=n;i>=1;i--)
book[a[i]]=i;//
線段樹
} build(
1,1,n);
for(int i=1;i<=q;i++)
else}}
線段樹的區間修改
1 include 2 include3 define lc p 1 該節點的左孩子 4 define rc p 1 1 右孩子5 using namespace std 67 很類似與樹狀陣列 8int n,m 9struct segment tree 10tree 1000000 線段樹陣列 1...
線段樹的區間加法與區間乘法
題目描述 如題,已知乙個數列,你需要進行下面兩種操作 將某區間每乙個數加上 kk。求出某區間每乙個數的和。輸入格式 第一行包含兩個整數 n,mn,m,分別表示該數列數字的個數和操作的總個數。第二行包含 nn 個用空格分隔的整數,其中第 ii 個數字表示數列第 ii 項的初始值。接下來 mm 行每行包...
線段樹的區間操作 板
區間操作 struct node tr maxn 2 節點型別 void pushup int m void build int m,int l,int r 如果只有乙個節點 int mid l r 1 build m 1,l,mid build m 1 1,mid 1,r 建好左右半邊 pushu...