題目鏈接:BZOJ3626
題目大意
給出一棵樹,若干個詢問:
分析
比較巧妙的一道題。
1. 首先定義一個操作
2. 考慮兩個點
3. 而且可以用前綴和的形式離線求解:依次對每個點進行
上代碼
#include <vector>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 5e4 + 10;
const int MOD = 201314;
int n, m;
inline int read() {
char ch;
int ans = 0, neg = 1;
while (!isdigit(ch = getchar()))
if (ch == '-') neg = -1;
while (isdigit(ch))
ans = ans * 10 + ch - '0', ch = getchar();
return ans * neg;
}
vector <int> edge[N];
int fa[N], son[N], dep[N], size[N];
int top[N], plc[N], replc[N], cntSeg;
void dfs1(int a, int par) {
fa[a] = par, dep[a] = dep[par] + 1, size[a] = 1;
for (int i = 0; i < edge[a].size(); i++) {
int now = edge[a][i];
if (now == par) continue;
dfs1(now, a), size[a] += size[now];
if (size[now] > size[son[a]]) son[a] = now;
}
}
void dfs2(int a, int up) {
top[a] = up, plc[a] = ++cntSeg, replc[cntSeg] = a;
if (son[a]) dfs2(son[a], up);
for (int i = 0; i < edge[a].size(); i++) {
int now = edge[a][i];
if (now == fa[a] || now == son[a]) continue;
dfs2(now, now);
}
}
int add[N * 3], tot[N * 3];
#define lc(a) ((a) << 1)
#define rc(a) (lc(a) | 1)
#define Len(l, r) ((r) - (l) + 1)
inline void pushUp(int a) {
tot[a] = tot[lc(a)] + tot[rc(a)];
}
inline void pushDown(int a, int l, int r) {
int mid = (l + r) >> 1;
add[lc(a)] += add[a], add[rc(a)] += add[a];
tot[lc(a)] = (tot[lc(a)] + add[a] * Len(l, mid)) % MOD;
tot[rc(a)] = (tot[rc(a)] + add[a] * Len(mid + 1, r)) % MOD;
add[a] = 0;
}
void modify(int a, int l, int r, int ll, int rr) {
if (l == ll && r == rr) {
add[a] = (add[a] + 1 == MOD ? 0 : add[a] + 1);
return tot[a] = (tot[a] + Len(l, r)) % MOD, void(0);
}
pushDown(a, l, r);
int mid = (l + r) >> 1;
if (rr <= mid) modify(lc(a), l, mid, ll, rr);
else if (ll > mid) modify(rc(a), mid + 1, r, ll, rr);
else modify(lc(a), l, mid, ll, mid), modify(rc(a), mid + 1, r, mid + 1, rr);
pushUp(a);
}
int query(int a, int l, int r, int ll, int rr) {
if (l == ll && r == rr) return tot[a];
pushDown(a, l, r);
int mid = (l + r) >> 1;
if (rr <= mid) return query(lc(a), l, mid, ll, rr);
else if (ll > mid) return query(rc(a), mid + 1, r, ll, rr);
return query(lc(a), l, mid, ll, mid) + query(rc(a), mid + 1, r, mid + 1, rr);
}
inline void decomMdf(int a, int b) {
while (top[a] != top[b]) {
if (dep[top[a]] < dep[top[b]]) swap(a, b);
modify(1, 1, n, plc[top[a]], plc[a]);
a = fa[top[a]];
}
if (dep[a] < dep[b]) swap(a, b);
return modify(1, 1, n, plc[b], plc[a]);
}
inline int decomTot(int a, int b) {
int ans = 0;
while (top[a] != top[b]) {
if (dep[top[a]] < dep[top[b]]) swap(a, b);
ans += query(1, 1, n, plc[top[a]], plc[a]);
a = fa[top[a]];
}
if (dep[a] < dep[b]) swap(a, b);
return ans + query(1, 1, n, plc[b], plc[a]);
}
struct Ask {
int poi, *plc;
Ask(int _poi = 0, int *_plc = 0): poi(_poi), plc(_plc) {}
}; vector <Ask> ask[N];
struct Ans {
int plus, minus;
inline void output() {
plus = (plus - minus) % MOD;
printf("%d\n", plus < 0 ? plus + MOD : plus);
}
} ans[N];
void init() {
n = read(), m = read();
for (int i = 2; i <= n; i++) {
int a = read() + 1;
edge[i].push_back(a), edge[a].push_back(i);
}
dfs1(1, 0), dfs2(1, 1);
for (int i = 1; i <= m; i++) {
int l = read() + 1, r = read() + 1, a = read() + 1;
ask[r].push_back(Ask(a, &ans[i].plus));
ask[l - 1].push_back(Ask(a, &ans[i].minus));
}
}
void figure() {
for (int i = 1; i <= n; i++) {
decomMdf(1, i);
for (int j = 0; j < ask[i].size(); j++) {
int tmp = ask[i][j].poi;
*ask[i][j].plc = decomTot(1, tmp);
}
}
for (int i = 1; i <= m; i++) ans[i].output();
}
int main() {
init();
figure();
return 0;
}
以上