九校聯考DAT2T3 啟發式合併,倍增

2021-08-28 00:09:00 字數 3141 閱讀 9189

南極的企鵝王國大學中生活著 n 只企鵝,作為 21 世紀的優秀大學生, 企鵝們積極響應「大眾創業,萬眾創新」的號召,紛紛創業。但是創業需要資 金,企鵝們最近手頭比較緊,只能互相借錢。

企鵝的借錢行為是有規律可循的:每只企鵝只會借一次錢,並且只會 從乙隻企鵝那裡借錢。借錢關係中不存在環(即不存在類似「金企鵝欠銀企 鵝錢,銀企鵝欠銅企鵝錢,銅企鵝欠金企鵝錢」這種情況)。

企鵝的還錢行為也是有規律可循的:每只企鵝一旦新獲得了一筆錢,就會立刻用這筆錢盡可能償還自己欠的債務,直到債務償清或用光這筆錢。它只會使用新獲得的這筆錢,至於以前它有沒有錢、有多少錢,與還錢行為無關。

企鵝們經常會做美夢。在乙隻企鵝 a 的夢裡,它夢見自己創業成功,一下子獲得了 +∞

+

∞元錢,於是(按照上文的還錢規則)它趕快把錢用來還債, 接著拿到錢的那只企鵝也趕快把錢用來還債……如此往復,直到所有獲得錢的企鵝都完成了還債操作。夢醒之後,它開心地把夢的內容告訴了另外乙隻企鵝 b,企鵝 b 聽了,也很開心,於是它問道:在你的夢裡,我獲得了多少錢呢?(指 b 去還債之前手裡的錢,包括後來用於還債的錢和還債後 b 手裡剩下的錢。)

夢畢竟是夢,對實際的欠債情況沒有影響。

第一行兩個整數 n 和 m,表示有 n 只企鵝,m 個操作。接下來 m 行,有兩種可能的格式:

-0 a b c:修改操作,企鵝 a 向企鵝 b 借了 c 元錢。

-1 a b:查詢操作, 詢問假如 a 有了 +∞

+

∞元錢,企鵝 b 會淨收入多少錢。

a = (a + lastans) % n + 1;

b = (b + lastans) % n + 1;

c = (c + lastans) % n + 1;

其中,lastans 是上一次詢問的答案。如果沒有上一次詢問,lastans 為0。

對每個詢問操作,輸出一行乙個數表示答案。

input

5 9

0 1 2 1

0 0 1 2

1 0 1

1 2 4

0 2 1 1

1 2 0

0 3 1 0

1 4 2

1 3 4

output

320

10

資料分為以下幾種:

第一種:佔 10%,n≤5000 且 m≤10000;

第二種:佔 20%,所有借錢事件(0 開頭的操作)發生在所有詢問事件(1 開頭的操作)之前;

第三種:佔 30%,對於乙隻企鵝 a,最多只有乙隻企鵝向 a 借錢;

第四種:佔 40%,沒有特殊性質,n、m 大小有一定梯度。

對於所有資料,滿足:n ≤ 105105

,m ≤ 106106

,0 ≤ a, b, c ≤ n 且 a ≠ b。

時間限制:1s

1

s空間限制:

512mb

512mb

一種比較顯然的做法是每次暴力維護倍增陣列

在資料隨機的時候會被卡成zz

考慮怎麼優化這個過程

啟發式合併。

我們把樹看成無根樹,額外維護乙個倍增陣列表示走2i

2

i的了路徑上的邊的方向

這樣就可以合併了。

複雜度o(n

log2

n)o (n

log2

n)

#include

using namespace std;

#define rep(i,j,k) for(int i = j;i <= k;++i)

#define repp(i,j,k) for(int i = j;i >= k;--i)

#define rept(i,x) for(int i = linkk[x];i;i = e[i].n)

#define p pair

#define pil pair

#define pli pair

#define pll pair

#define pb push_back

#define pc putchar

#define mp make_pair

#define file(k) memset(k,0,sizeof(k))

#define ll long long

const

int inf = 1e9;

namespace fastio

}return *p1++;

}inline bool blank(char ch)

inline void read(int &x)

inline void read(ll &x)

#undef out_size

#undef buf_size

};using namespace fastio;

int lastans,n,m;

int f[101000][20] , mn[101000][20] , di[101000][20];

int size[101000] , bel[101000] , dep[101000];

int linkk[101000],t;

struct nodee[201000];

int min(int a,int b)

void add(int x,int y,int z)

void dfs(int x,int fa,int root)

}void insert(int a,int b,int c)

int query(int x,int y)

if(x == y) return ans;

repp(i,17,0)

if(f[x][i] != f[y][i])

if(di[x][0] != d || di[y][0] != (d^3)) return

0; ans = min(ans,min(mn[x][0],mn[y][0]));

return ans;

} int main()

return

0;}

還有一種比較神的做法是用vector存同一深度的點再用鍊錶串起來,再啟發式合併,能優化掉乙個lo

g log

DP 三校聯考1017T3

考場上這題做了我兩個小時。果然第一步都錯了。首先,所謂的絕對值其實可以用最優性忽略!即 a b max a b,b a 所以,不必考慮到底誰大誰小,在最優策略中,一定是合法的。然後就很簡單了 每乙個位置的貢獻分別可能為2,0,2 開頭末尾可能為 1,1 一段連續的2或 2就是一段。這麼搞一下dp就行...

多校聯考2 T3 排列 DP

dp 對於乙個排列,考慮相鄰的兩個元素,如果後面乙個比前面乙個大,表示這個位置是上公升的,用 i 表示,反之這個位置是下降的,用 d表示。如排列 3,1,2,7,4,6,5 可以表示為 diidid。現在給出乙個長度為 n 1的排列表示,問有多少種 1 到n 的排列滿足這種表示。乙個字串 s,s 由...

五校聯考3day2 A

這題考場考慮不太全 但相比於60,其它90分的人,還是很全的 long long我是開了的,然後後面的特判我也是加了的,可是竟然打錯了?其實這題不需要打的像我這樣麻煩 設a i 表示i點還需連線的邊數 ans表示sigma a i max表示max a i 如果max ans 2,就說明全部連項那個...