HYSBZ 5145 未來日記

2021-09-27 11:42:57 字數 3649 閱讀 1543

題意:

給定乙個長為 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 順時針或逆時針旋轉乙個位置,計...