1. 程式人生 > >Luogu 3241 [HNOI2015]開店

Luogu 3241 [HNOI2015]開店

BZOJ 4012許可權題

浙科協的網突然炸了,好慌……

據說正解是動態點分治,然而我並不會,我選擇樹鏈剖分 + 主席樹維護。

設$dis_i$表示$i$到$root(1)$的值,那麼對於一個詢問$u$,答案為$\sum_{i = 1}^{n}dis_i + n * dis_u - 2 * \sum_{i = 1}^{n}dis_{lca(i, u)}$。

前兩個東西很好維護,我們考慮如何維護後面這個$\sum$,對於每一個點我們可以把它到根跳一跳,然後把這個點對答案的貢獻加到線段樹中,如果再限定一個$[l, r]$的區間,只要把所有年齡排序從小到大排序按照貢獻加到主席樹中就可以了。

注意一條樹鏈的貢獻和線段樹上區間的邊界要搞清楚。

主席樹標記永久化一下比較好,雖然感覺空間是開不下的,但是這題就這麼過去了。

時間複雜度$O((n + q)log^2n)$。

Code:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;

const int N = 1.5e5 + 5;
const int M = 1e7 + 100;
const int inf = 1 << 30;

int n, qn, tot = 0
, head[N], dfsc = 0, dep[N]; int top[N], fa[N], siz[N], son[N], id[N]; ll P, dis[N], toVal[N], sumE[N], sumDis[N]; struct Edge { int to, nxt; ll val; } e[N << 1]; inline void add(int from, int to, ll val) { e[++tot].to = to; e[tot].val = val; e[tot].nxt = head[from
]; head[from] = tot; } struct Item { int age, id; friend bool operator < (const Item &x, const Item &y) { if(x.age == y.age) return x.id < y.id; else return x.age < y.age; } } a[N]; template <typename T> inline void read(T &X) { X = 0; char ch = 0; T op = 1; for(; ch > '9' || ch < '0'; ch = getchar()) if(ch == '-') op = -1; for(; ch >= '0' && ch <= '9'; ch = getchar()) X = (X << 3) + (X << 1) + ch - 48; X *= op; } inline void swap(int &x, int &y) { int t = x; x = y; y = t; } inline int max(int x, int y) { return x > y ? x : y; } inline int min(int x, int y) { return x > y ? y : x; } void dfs1(int x, int fat, int depth, ll nowDis) { fa[x] = fat, dep[x] = depth; siz[x] = 1, dis[x] = nowDis; int maxson = -1; for(int i = head[x]; i; i = e[i].nxt) { int y = e[i].to; if(y == fat) continue; dfs1(y, x, depth + 1, nowDis + e[i].val); toVal[y] = e[i].val; siz[x] += siz[y]; if(siz[y] > maxson) { maxson = siz[y]; son[x] = y; } } } void dfs2(int x, int topf) { top[x] = topf, sumE[id[x] = ++dfsc] = toVal[x]; if(!son[x]) return; dfs2(son[x], topf); for(int i = head[x]; i; i = e[i].nxt) { int y = e[i].to; if(y == fa[x] || y == son[x]) continue; dfs2(y, y); } } namespace PSegT { struct Node { int lc, rc; ll sum, cnt; } s[M]; int root[N], nodeCnt = 0; #define lc(p) s[p].lc #define rc(p) s[p].rc #define sum(p) s[p].sum #define cnt(p) s[p].cnt #define mid ((l + r) >> 1) void ins(int &p, int l, int r, int x, int y, int pre) { s[p = ++nodeCnt] = s[pre]; if(x <= l && y >= r) { ++cnt(p); return; } sum(p) += sumE[min(y, r)] - sumE[max(x, l) - 1]; if(x <= mid) ins(lc(p), l, mid, x, y, lc(pre)); if(y > mid) ins(rc(p), mid + 1, r, x, y, rc(pre)); } ll query(int p, int l, int r, int x, int y) { ll res = 1LL * cnt(p) * (sumE[min(y, r)] - sumE[max(x, l) - 1]); if(x <= l && y >= r) return res + sum(p); if(x <= mid) res += query(lc(p), l, mid, x, y); if(y > mid) res += query(rc(p), mid + 1, r, x, y); return res; } } using namespace PSegT; inline void modify(int rt, int x) { for(; x; x = fa[top[x]]) ins(root[rt], 1, n, id[top[x]], id[x], root[rt]); } inline ll solve(int rt, int x) { ll res = 0LL; for(; x; x = fa[top[x]]) res += query(root[rt], 1, n, id[top[x]], id[x]); return res; } int main() { // freopen("Sample.txt", "r", stdin); read(n), read(qn), read(P); for(int i = 1; i <= n; i++) { read(a[i].age); a[i].id = i; } for(int i = 1; i < n; i++) { int x, y; ll v; read(x), read(y), read(v); add(x, y, v), add(y, x, v); } dfs1(1, 0, 1, 0LL), dfs2(1, 1); /* for(int i = 1; i <= n; i++) printf("%d ", top[i]); printf("\n"); */ sort(a + 1, a + 1 + n); for(int i = 1; i <= n; i++) { sumE[i] += sumE[i - 1]; sumDis[i] = sumDis[i - 1] + dis[a[i].id]; } for(int i = 1; i <= n; i++) { root[i] = root[i - 1]; modify(i, a[i].id); } /* for(int i = 1; i <= n; i++) printf("%lld ", sumE[i]); printf("\n"); for(int i = 1; i <= n; i++) printf("%lld ", sumDis[i]); printf("\n"); */ ll ans = 0LL; for(int x, l, r; qn--; ) { read(x), read(l), read(r); l = (1LL * l + ans) % P, r = (1LL * r + ans) % P; if(l > r) swap(l, r); l = lower_bound(a + 1, a + 1 + n, (Item) {l, 0}) - a; r = upper_bound(a + 1, a + 1 + n, (Item) {r, inf}) - a - 1; ans = 1LL * (r - l + 1) * dis[x] + sumDis[r] - sumDis[l - 1] - 2LL * (solve(r, x) - solve(l - 1, x)); printf("%lld\n", ans); } return 0; }
View Code