題目傳送門
time limit: 20 sec
memory limit: 512 mb
submit: 5039
solved: 1751 [
submit][
status][
discuss]
有n個位置,m個操作。操作有兩種,每次操作如果是1 a b c的形式表示在第a個位置到第b個位置,每個位置加入乙個數c
如果是2 a b c形式,表示詢問從第a個位置到第b個位置,第c大的數是多少。
第一行n,m
接下來m行,每行形如1 a b c或2 a b c
輸出每個詢問的結果
2 51 1 2 1
1 1 2 2
2 1 1 2
2 1 1 1
2 1 2 312
1【樣例說明】
第乙個操作 後位置 1 的數只有 1 , 位置 2 的數也只有 1 。 第二個操作 後位置 1
的數有 1 、 2 ,位置 2 的數也有 1 、 2 。 第三次詢問 位置 1 到位置 1 第 2 大的數 是
1 。 第四次詢問 位置 1 到位置 1 第 1 大的數是 2 。 第五次詢問 位置 1 到位置 2 第 3
大的數是 1 。
n,m<=50000,n,m<=50000
a<=b<=n
1操作中abs(c)<=n
2操作中c<=maxlongint
題解
此題有兩種做法,一種是cdq分治,一種是樹套樹。由於樹套樹簡單清晰,這裡就先寫樹套樹的題解(其實是我還不會cdq分治)。
此題用線段樹套線段樹。外層線段樹表示權值,內層為該權值範圍在區間內的分布情況。
這樣在查詢時可以用類似二分的方法得到答案,更新時則先找到外層節點,再更新其節點內層樹。
在這裡我用的是永久化lazy標記,主要是擔心常數被卡。
#include const int maxn = 50000 + 10, ms = maxn << 8;
int root[maxn << 2], ls[ms], rs[ms], tot, n, m;
long long cnt[ms], ly[ms];
//線段樹的外層為權值,內層為區間
int ina; char inc; bool insign;
inline int geti()
void insert(int &u, int l, int r, int x, int y)
int mid = (l + r) >> 1;
if (y <= mid) insert(ls[u], l, mid, x, y);
else if (x > mid) insert(rs[u], mid + 1, r, x, y);
else
cnt[u] += y - x + 1;
}void add(int x, int y, int val)
}long long count(int u, int l, int r, int x, int y)
int query(int x, int y, long long val)
}int main()
return 0;
}
BZOJ 3110 k大數查詢 樹套樹
5e4個可重集合,初試全空,5e4個操作 1.在第 l,r 集合裡加入乙個數c 2.問 l,r 所有集合的並的第k大數 發現很多題解都寫得權值線段樹套區間線段樹啊,我覺得這題反過來套比較直白吧。不過寫了一半陷入了奇怪的思維漩渦裡。就跟著題解寫了個權值套區間線段樹,在luogu上開了o2,加了讀入掛,...
BZOJ 3110 K大數查詢 樹套樹
題目鏈結 權值線段樹套區間線段樹,權值線段樹的每個結點儲存該結點所表示的區間範圍內的數在各個區間的分布情況,查詢時在權值線段樹上二分即可。複雜度 o nlog 2n 注意區間線段樹需要動態開點,並且標記要永久化,否則會tle。另外就是sum可能會爆int,需要用long long儲存。1 inclu...
樹套樹 BZOJ 3110 K大數
通道 題意 有n個位置,m個操作。操作有兩種,每次操作如果是1 a b c的形式表示在第a個位置到第b個位置,每個位置加入乙個數c,如果是2 a b c形式,表示詢問從第a個位置到第b個位置,第c大的數是多少 思路 先開一顆權值線段樹。對於當前結點k,它表示了權值範圍為a b的所有結點的資訊。但是有...