題意:
給定乙個長為 n 的陣列 a,有 m 個操作,①:1,l,r,x,y,把區間 [ l, r ] 的所有 x 變成 y;②:2,l,r,k,查詢區間 [ l, r ] 的第 k 小值。(n, m, a
ia_i
ai <= 1e5)
解題思路:
直接考慮分塊(bushi)。 首先講一講靜態 / 動態區間 k 小 o(n
n)
o(n\sqrt)
o(nn)
的分塊做法 —— 值域分塊 (既然有樹套樹,那麼就有分塊套分塊)。 假定值域與 n 同階,將值域分成n
\sqrt
n塊,第 i 塊記錄值在範圍 [(i
−1)∗
n+1,
i∗n]
[(i - 1) * \sqrt + 1,i * \sqrt]
[(i−1)
∗n+
1,i∗
n] 的數的個數,這樣求 k 小時,先遍歷定位塊,在塊中逐值遍歷,複雜度 o(n
)o(\sqrt)
o(n
)。動態區間 k 小的話,需要記錄一下序列塊的值域塊字首和,修改時候維護字首和即可,複雜度也是 o(n
)o(\sqrt)
o(n)。
再回到原題的操作一,對單獨的塊,用並查集將值相同的位置鏈在一起,標記每個聯通塊是哪個值。對於整塊的修改,就是並查集的合併操作。但會有問題,比如 2 - > 3,1 - > 2,假如對 1 - > 2 直接合併,會導致 1 鏈結到 3,顯然錯誤。這個時候不進行合併,直接將 1 所在聯通塊的代表值改為 2 即可。對於散塊的修改,暴力重構 x、y 所在的聯通塊即可。
#include
using
namespace std;
typedef
long
long ll;
typedef pair<
int,
int> pii;
#define pb push_back
#define sz(a) ((int)a.size())
#define mem(a, b) memset(a, b, sizeof a)
#define lson (rt << 1)
#define rson (rt << 1 | 1)
#define gmid (l + r >> 1)
const
int maxn =
1e5+5;
const
int maxm =
333;
const
int mod =
1e9+7;
const
int inf =
0x3f3f3f3f
;const
int lenz =
333;
const
int lim =
1e5;
int li[maxm]
, ri[maxm]
, id[maxn]
;int lz[maxm]
, rz[maxm]
, idz[maxn]
;int sum[maxm]
[maxn]
, sumz[maxm]
[maxm]
;int pre[maxn]
, rt[maxm]
[maxn]
, val[maxn]
;int a[maxn]
, tp[maxn]
, tpz[maxm]
;int n, m;
void
init()
for(
int i =
1; i <= n;
++i)
}int
fin(
int x)
pii update2
(int p,
int l,
int r,
int x,
int y)
;int cnt1 =
0, cnt2 =0;
for(
int i = li[p]
; i <= ri[p]
;++i)
rt[p]
[x]= rt[p]
[y]=0;
for(
int i = li[p]
; i <= ri[p]
;++i)
else
if(val[i]
== y)
}return;}
void
update
(int l,
int r,
int x,
int y)
return;}
pii cnt =
update2
(p1, l, ri[p1]
, x, y)
;int res = sum[p1]
[x]- cnt.first, tmp;
sum[p1]
[x]-
= cnt.first, sum[p1]
[y]+
= cnt.first;
sumz[p1]
[idz[x]]-
= cnt.first, sumz[p1]
[idz[y]]+
= cnt.first;
for(
int i = p1 +
1; i < p2;
++i)
cnt =
update2
(p2, li[p2]
, r, x, y)
; res +
= cnt.second, tmp = sum[p2]
[x]- res;if(
!tmp)
return
;for
(int i = p2; i <= id[n]
;++i)
}void
cal(
int l,
int r,
int v)
}int
query
(int l,
int r,
int k)
break;}
cal(l, r,-1
);return ret;
}cal
(l, ri[p1],1
);cal(li[p2]
, r,1)
;for
(int i =
1; i <= idz[lim]
;++i)
break;}
cal(l, ri[p1],-
1);cal
(li[p2]
, r,-1
);return ret;
}const
int maxs =
1e3+5;
char buf[maxs]
,*p1 = buf,
*p2 = buf;
inline
charfr(
)#define gc fr()
inline
void
read
(int
&x)int
main()
return0;
}
514 柵欄染色
3.28 這個題自己的錯誤,廢了很多時間。如果是單純地相鄰不許同色的話,應該就是這樣的 public static int numways1 int n,int k if k 1 n 2 int x int math.pow k 1,n 1 return x k 2 n 1 如果是不允許三根柱子相鄰...
514 柵欄染色
從物理學到計算機,再到硬體,再到人工智慧!藍橋杯備賽 lintcode上刷的第三題 我們有乙個柵欄,它有n個柱子,現在要給柱子染色,有k種顏色可以染。必須保證不存在超過2個相鄰的柱子顏色相同,求有多少種染色方案。最開始,我想用動態陣列儲存每一種方案的第i根柱子的顏色。後來發現這樣資料量太大,而且記錄...
514 自由之路
最初,ring 的第乙個字元與12 00方向對齊。您需要順時針或逆時針旋轉 ring 以使 key 的乙個字元在 12 00 方向對齊,然後按下中心按鈕,以此逐個拼寫完 key 中的所有字元。旋轉 ring 拼出 key 字元 key i 的階段中 您可以將 ring 順時針或逆時針旋轉乙個位置,計...