雨天的尾巴

2022-02-15 20:32:59 字數 2880 閱讀 7035

acwing連線(bzoj3307)

深繪里一直很討厭雨天。

灼熱的天氣穿透了前半個夏天,後來一場大雨和隨之而來的洪水,澆滅了一切。

雖然深繪里家鄉的小村落對洪水有著頑固的抵抗力,但也倒了幾座老房子,幾棵老樹被連根拔起,以及田地裡的糧食被弄得一片狼藉。

無奈的深繪里和村民們只好等待救濟糧來維生。

不過救濟糧的發放方式很特別。

有 n 個點,形成乙個樹狀結構。

有 m 次發放操作,每次選擇兩個點 x,y,對 x 到 y 的路徑上(包括 x,y)的每個點發放一袋 z 型別的物品。

求完成所有發放操作後,每個點存放最多的是哪種型別的物品。

第一行兩個正整數n,m,含義如題目所示。

接下來n-1行,每行兩個數(a,b),表示(a,b)間有一條邊。

再接下來m行,每行三個數(x,y,z),含義如題目所示。

共n行,第i行乙個整數,表示第i座房屋裡存放的最多的是哪種救濟糧,如果有多種救濟糧存放次數一樣,輸出編號最小的。

如果某座房屋裡沒有救濟糧,則對應一行輸出0。

1≤n,m≤100000,

1≤z≤10^9

5 3

1 23 1

3 45 3

2 3 3

1 5 2

3 3 3

233

02

需要掌握 樹上lca 和 動態開點線段樹

思想 差分, 離散化

根據題意明顯是 區間操作, 對於樹, 那麼就是樹上差分 和 樹剖 了

對於 (x, y) 增加 z, 根據差分, 思考發現, ++val[x][z], ++val[y][z], --val[lca(x, y)][z], --val[lca(x, y)的父節點][z], 可以在樹上線性跑出 每個節點 z 的數量

而 z 異常的大, 1e9, 而 m 只有1e5, 明顯需要離散化, 降低 z 的範圍

就算如此 對於每個節點 跑出 每個z的數量也是 **的

我們就要想到 log 級別的方法, 那就線段樹了, 然而肯定會爆記憶體, 所以要動態開點

對於節點數, 4 * m * log2(z(離散化)), 每個節點佔 12位元組, 在加上亂七八糟的lca和存輸入的陣列, 記憶體也不會太緊張(你要是節點東西多了, 會爆, 還是有點卡記憶體的)

#include #define all(n) (n).begin(), (n).end()

#define se second

#define fi first

#define pb push_back

#define mp make_pair

#define sqr(n) (n)*(n)

#define rep(i,a,b) for(int i=(a);i<=(b);++i)

#define per(i,a,b) for(int i=(a);i>=(b);--i)

#define io ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr)

using namespace std;

typedef long long ll;

typedef pairpii;

typedef pairpll;

typedef vectorvi;

typedef double db;

const int n = 1e5 + 5, m = 7e6 + 5;

int n, m, _, k;

int h[n], ne[n << 1], to[n << 1], tota;

int dep[n], f[n][20], t;

int x[n], y[n], z[n], tax[n], tot, ans[n];

void add(int u, int v)

void bfs(int s) }}

int lca(int x, int y)

struct node tr[m];

int node, rt[n];

void push_up(int root)

void update(int& root, int l, int r, int val, int d)

int mid = (l + r) >> 1;

if (mid >= val) update(tr[root].l, l, mid, val, d);

else update(tr[root].r, mid + 1, r, val, d);

push_up(root);

}int merge(int a, int b)

tr[a].l = merge(tr[a].l, tr[b].l);

tr[a].r = merge(tr[a].r, tr[b].r);

push_up(a);

return a;

}int query(int root, int l, int r)

void dfs(int u, int fa)

ans[u] = tax[query(rt[u], 1, tot)];

}int main()

bfs(1);

rep(i, 1, m) cin >> x[i] >> y[i] >> z[i], tax[i] = z[i];

sort(tax + 1, tax + 1 + m);

tot = unique(tax + 1, tax + 1 + m) - tax - 1;

rep(i, 1, m)

dfs(1, 0);

rep(i, 1, n) cout << ans[i] << '\n';

return 0;

}

雨天的尾巴

考試的時候直接扎第一題上了這到題連暴力都沒打出來t t 心路歷程 其實考試時候還是有可能做出來的,當然關鍵在能否想到線段樹合併。當時想到了離散化 很慌沒打出來。樹上差分,lca倍增,當時覺滴倍增很難打,一看n 100000,於是選擇 用向上標記法,然而少了一行 爆零兩行淚。現在看來倍增真是一點不難啊...

雨天的尾巴題目解析

考試的時候直接扎第一題上了這到題連暴力都沒打出來t t 心路歷程 其實考試時候還是有可能做出來的,當然關鍵在能否想到線段樹合併。當時想到了離散化 很慌沒打出來。樹上差分,lca倍增,當時覺滴倍增很難打,一看n 100000,於是選擇 用向上標記法,然而少了一行 爆零兩行淚。現在看來倍增真是一點不難啊...

bzoj3307 雨天的尾巴

time limit 10 sec memory limit 128 mb submit 258 solved 121 submit status discuss n個點,形成乙個樹狀結構。有m次發放,每次選擇兩個點x,y 對於x到y的路徑上 含x,y 每個點發一袋z型別的物品。完成 所有發放後,每...