T1004 a*b problem(HDU 7448)
不會。
T1005 小塔的養成遊戲之夢(HDU 7449)
不會。
T1009 強攻計策(HDU 7453)
容易發現初始速度是多少對答案沒有影響,所以我們預設初始速度為 \(0\)。題意相當於在平面直角座標系上(橫軸為時間,縱軸為速度),有一個目標高度,維護一條儘量接近目標的直線,但斜率只能是 \(-1/0/1\),要支援一段區間目標 \(+1\),求直線下方面積。
將一次區間 \(+1\) 拆成一段字尾 \(+1\) 和一段字尾 \(-1\)。注意到一次字尾 \(+1/-1\) 時至多隻有一個位置發生向上/向下翻折,在這個位置前與目標的相對高度 \(-1/+1\),之後相對高度不變,那麼此時面積的變化量容易用這個位置表示,我們現在的任務就是快速找到這個位置。
具體而言,設 \(h_i\) 表示直線在 \(x = i\) 處的相對高度,手玩容易發現當區間 \(+1\) 時,我們要找第一個 \(0/-1\),區間 \(-1\) 時,我們要找第一個 \(0/1\)。
現在我們要維護一個資料結構,支援區間 \(+1/-1\),區間找第一個 \(-1/0/1\),考慮分塊,塊內維護排序陣列,修改時整塊打標記,散塊歸併重構,詢問時散塊暴力,整塊二分即可,平衡塊長,時間複雜度 \(O(n \sqrt {n \log n})\),常數較小。
Code
#include <iostream>
#include <cmath>
#include <numeric>
#include <algorithm>
#include <vector>
using namespace std;
using LL = long long;
const int N = 1e5 + 5;
const int Mod = 1e9 + 7, Inv = (Mod + 1) / 2;
int n, m;
LL ans;
namespace Block {
int len, cnt;
int a[N], b[N], tag[N], bl[N], L[N], R[N];
void build () {
len = sqrt(n) * 0.4;
for (int i = 0; i <= n; ++i) {
bl[i] = i / len + 1;
}
cnt = bl[n];
R[0] = -1;
for (int i = 1; i <= cnt; ++i) {
L[i] = R[i - 1] + 1;
R[i] = min(n, L[i] + len - 1);
}
fill(a, a + n + 1, 0);
iota(b, b + n + 1, 0);
fill(tag, tag + cnt + 1, 0);
}
int first_val (int x, int y) {
for (int i = x; i <= R[bl[x]]; ++i) {
if (a[i] == y - tag[bl[x]]) {
return i;
}
}
for (int i = bl[x] + 1; i <= cnt; ++i) {
if (a[b[R[i]]] < y - tag[i] || a[b[L[i]]] > y - tag[i]) continue;
auto cmp = [&](int i, int j) -> bool {
return a[i] < j;
};
auto it = lower_bound(b + L[i], b + R[i] + 1, y - tag[i], cmp);
if (it != b + R[i] + 1 && a[*it] == y - tag[i]) return *it;
}
return n + 1;
}
int tmpa[N][2];
int al[2];
void add (int l, int r, int x) {
r = min(r, n);
auto rebuild = [&](int l, int r, int gl, int gr) -> void {
al[0] = 0, al[1] = 0;
for (int i = l; i <= r; ++i) {
int o = b[i] >= gl && b[i] <= gr;
tmpa[++al[o]][o] = b[i];
}
int p = l;
auto cmp = [&](int i, int j) -> bool {
return a[i] < a[j] || a[i] == a[j] && i < j;
};
for (int cur[2] = {1, 1}; cur[0] != al[0] + 1 || cur[1] != al[1] + 1; ) {
if (cur[0] != al[0] + 1 && (cur[1] == al[1] + 1 || cmp(tmpa[cur[0]][0], tmpa[cur[1]][1]))) {
b[p++] = tmpa[cur[0]][0], ++cur[0];
}
else {
b[p++] = tmpa[cur[1]][1], ++cur[1];
}
}
};
if (bl[l] == bl[r]) {
for (int i = l; i <= r; ++i) {
a[i] += x;
}
rebuild(L[bl[l]], R[bl[l]], l, r);
}
else {
for (int i = l; i <= R[bl[l]]; ++i) {
a[i] += x;
}
for (int i = L[bl[r]]; i <= r; ++i) {
a[i] += x;
}
rebuild(L[bl[l]], R[bl[l]], l, R[bl[l]]);
rebuild(L[bl[r]], R[bl[r]], L[bl[r]], r);
for (int i = bl[l] + 1; i <= bl[r] - 1; ++i) {
tag[i] += x;
}
}
}
}
void suf_add (int x) {
int pos = min(Block::first_val(x, 0), Block::first_val(x, 1));
ans += max(0, (n - pos) * 2 - 1);
Block::add(x, pos, -1);
}
void suf_minus (int x) {
int pos = min(Block::first_val(x, 0), Block::first_val(x, -1));
ans -= max(0, (n - pos) * 2 - 1);
Block::add(x, pos, 1);
}
int main () {
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
int T;
cin >> T;
while (T--) {
cin >> n >> m;
Block::build(), ans = 0;
for (int i = 1, l, r; i <= m; ++i) {
cin >> l >> r;
suf_add(l), suf_minus(r);
cout << ans % Mod * Inv % Mod << '\n';
}
}
return 0;
}
T1012 圖計算(HDU 7456)
考慮對於每一張圖分別維護並查集,我們使用啟發式合併,這樣可以保證每個結點的 \(fa\) 就是它的最高階祖先,對於每一個結點,為它在所有圖中的 \(fa\) 序列雜湊即可。
Code
#include <iostream>
#include <vector>
#include <tuple>
#include <unordered_map>
using namespace std;
using LL = long long;
using Tp = tuple<int, int, int>;
const int N = 5e4 + 5, M = 105;
int n, m, d, q;
struct Hash_Arr {
int len;
struct Hash {
int mod, base, len;
int pw[M], now;
void init (int mod_, int base_, int len_) {
mod = mod_, base = base_, now = 0, len = len_;
pw[0] = 1;
for (int i = 1; i <= len; ++i) {
pw[i] = 1ll * pw[i - 1] * base % mod;
}
}
void add (int x, int y) { now = (now + 1ll * (mod + y) * pw[x]) % mod; }
} ha[3];
void init (int len_) {
len = len_;
ha[0].init(1000000007, 1000000009, len);
ha[1].init(1000000021, 1000000033, len);
ha[2].init(1000000087, 1000000093, len);
}
void add (int x, int y) {
ha[0].add(x, y);
ha[1].add(x, y);
ha[2].add(x, y);
}
Tp get_val () { return make_tuple(ha[0].now, ha[1].now, ha[2].now); }
} h[N];
struct tHash {
const int tB = 998244353, tP = tB * tB;
int operator() (Tp x) const {
return get<0>(x) + get<1>(x) * tB * get<2>(x) * tP;
}
};
unordered_map<Tp, int, tHash> p;
LL ans;
void add (Tp x) {
int v = p[x]++;
ans += v;
}
void remove (Tp x) {
int v = --p[x];
ans -= v;
}
struct U {
int fa[N], id;
vector<int> vec[N];
void init (int id_) {
id = id_;
fill(vec + 1, vec + n + 1, vector<int>());
for (int i = 1; i <= n; ++i) {
vec[i].push_back(i);
fa[i] = i;
h[i].add(id, i);
}
}
void unite (int x, int y) {
x = fa[x], y = fa[y];
if (x == y) return;
if (vec[x].size() < vec[y].size()) swap(x, y);
for (auto v : vec[y]) {
vec[x].push_back(v);
remove(h[v].get_val());
h[v].add(id, x - fa[v]);
add(h[v].get_val());
fa[v] = x;
}
vec[y].clear();
}
} uf[M];
int main () {
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
int T;
cin >> T;
while (T--) {
cin >> n >> m >> d >> q;
for (int i = 1; i <= n; ++i) {
h[i].init(d + 1);
}
for (int i = 1; i <= d + 1; ++i) {
uf[i].init(i);
}
p.clear(), ans = 0;
for (int i = 1; i <= n; ++i) {
add(h[i].get_val());
}
for (int i = 1, u, v; i <= m; ++i) {
cin >> u >> v;
for (int j = 1; j <= d + 1; ++j) {
uf[j].unite(u, v);
}
}
for (int i = 1, u, v, w; i <= q; ++i) {
cin >> u >> v >> w;
uf[w].unite(u, v);
cout << ans << '\n';
}
}
return 0;
}