P4211 [LNOI2014] LCA 树链剖分+扫描线
这道题目主要是运用了一个很好的 trick。 \(dep_{LCA(x,y)}\) 可以这样想,将根( \(1\) )到 \(x\) 的路径上的值全部加一,然后求 \(1\) 到 \(y\) 路径上的值。那么这道题目就被转化为了一个类似扫描线的问题。
这个 trick 为这题 90% 的难度。因此开一个 trick 合集吧。
#include <bits/stdc++.h>
#define debug puts("Wait for me.");
template <typename T>void read(T& t){t=0; char ch=getchar(); int fflag=1;while(!('0'<=ch&&ch<='9')){if(ch=='-') fflag=-1;ch=getchar();}while(('0'<=ch&&ch<='9')){t=t*10+ch-'0'; ch=getchar();} t*=fflag;}
template <typename T,typename... Args>void read(T& t, Args&... args){read(t);read(args...);}
template <typename T>void write(const T &x) {if(x < 10) {putchar(x + '0');return;}write(x / 10);putchar(x % 10 + '0');}
#define pb push_back
using namespace std;
#define rep(I,J,K) for(int I=(int)J;I<=(int)K;++I)
#define per(I,J,K) for(int I=(int)J;I>=(int)K;--I)
typedef long long ll;typedef double db;typedef pair<int,int>pii;
mt19937 mrand(random_device{}());
int rnd(int x){return mrand()%x;}
// head
const int N = 5e4 + 10,inf = 0x3f3f3f3f, P = 201314;
int n, m, dfn[N], zr[N], sz[N], top[N], _dfn[N];
vector<int>G[N];
struct Ques {
int x, z, id, fh;
bool operator < (const Ques &ques) const {
return x < ques.x;
}
}Q[N << 1];
int cnt = 0, tot = 0, ans[N], fa[N];
void add(int &x, int y) {x += y; if(x >= P) x -= P;}
void del(int &x, int y) {x -= y; if(x < 0) x += P;}
struct Fenwick_Tree {
int val1[N], val2[N];
int lowbit(int x) {return x & (-x);}
void modify(int x, int va,int val[]) {
while(x <= n) {
if(va > 0) add(val[x], va);
if(va < 0) del(val[x], -va);
x += lowbit(x);
}
}
void modify(int l, int r, int va) {
// 给区间 l 到 r 加上 va
modify(l, va, val1); modify(r + 1, -va, val1);
modify(l, va * l % P, val2); modify(r + 1, -((r + 1) * va % P), val2);
}
int query(int x, int val[]) {
if(x == -1) return 0;
int res = 0;
while(x) {
add(res, val[x]);
// cout << x << endl;
x -= lowbit(x);
}
return res;
}
int Query(int x) {
return ((ll)(x + 1) * query(x, val1) % P - query(x, val2) + P) % P;
}
int Query(int l, int r) {
return (Query(r) - Query(l - 1) + P) % P;
}
}bit;
void dfs(int u) {
sz[u] = 1;
for(int v : G[u]) {
dfs(v);
sz[u] += sz[v];
if(sz[v] > sz[zr[u]]) zr[u] = v;
}
}
void dfs2(int u, int tp) {
top[u] = tp; _dfn[dfn[u] = ++cnt] = u;
if(zr[u]) dfs2(zr[u], tp);
for(int v : G[u]) if(v != zr[u]) dfs2(v, v);
}
int Query(int x) {
// 查询 1-x 路径上的权值和
if(x == 0) return 0;
int res = 0;
while(top[x] != 1) {
// cout << x << endl;
add(res, bit.Query(dfn[top[x]], dfn[x]));
x = fa[top[x]];
}
add(res, bit.Query(dfn[top[x]], dfn[x]));
return res;
}
void modify(int x) {
// 1-x 路径上权值全部加一
while(top[x] != 1) bit.modify(dfn[top[x]], dfn[x], 1), x = fa[top[x]];
bit.modify(dfn[top[x]], dfn[x], 1);
return;
}
int main(){
read(n, m);
rep(i, 2, n) {
read(fa[i]);
++fa[i];
G[fa[i]].pb(i);
}
dfs(1);
dfs2(1, 1);
rep(i, 1, m) {
int l, r, z;
read(l, r, z);
++l, ++r; ++z;
Q[++tot] = {l - 1, z, i, -1};
Q[++tot] = {r, z, i, 1};
}
sort(Q + 1, Q + tot + 1);
int cur = 1;
rep(i, 0, n) {
if(i) modify(i);
while(cur <= tot && Q[cur].x <= i) {
if(Q[cur].fh == 1) add(ans[Q[cur].id], Query(Q[cur].z));
else del(ans[Q[cur].id], Query(Q[cur].z));
++cur;
}
}
rep(i, 1, m) cout << ans[i] << endl;
return 0;
}

浙公网安备 33010602011771号