Bzoj3626 [LNOI2014]LCA
先把问题简化,怎样求一个点x和y的lca的deep和
显然直接求LCA,但是这样的话,要求多个就不好叠加
于是可以用奇技淫巧:先把x到根的所有点打上标记,那么询问y到根的标记的个数即为答案,这样就可以叠加
所以对于询问,拆成[1,l-1], [1, r],排序后依次加点覆盖标记即可
可以用树链剖分+线段树,或者Orz yyb大佬一样写LCT
代码
表示不想写LCT
# include <bits/stdc++.h>
# define RG register
# define IL inline
# define Fill(a, b) memset(a, b, sizeof(a))
using namespace std;
typedef long long ll;
const int _(1e5 + 10), __(1e6 + 10), INF(2e9), MOD(201314);
IL ll Read(){
char c = '%'; ll x = 0, z = 1;
for(; c > '9' || c < '0'; c = getchar()) if(c == '-') z = -1;
for(; c >= '0' && c <= '9'; c = getchar()) x = x * 10 + c - '0';
return x * z;
}
int n, q, cnt, fst[_], to[_], nxt[_], fa[_], son[_], size[_], top[_], deep[_], dfn[_];
int sum[__], tag[__], ans[_], z[_];
struct Data{
int f, id, type;
IL bool operator <(RG Data B) const{ return f < B.f; }
} qry[_];
IL void Add(RG int u, RG int v){ to[cnt] = v; nxt[cnt] = fst[u]; fst[u] = cnt++; }
IL void Dfs1(RG int u){
size[u] = 1;
for(RG int e = fst[u]; e != -1; e = nxt[e]){
if(size[to[e]]) continue;
deep[to[e]] = deep[u] + 1; fa[to[e]] = u;
Dfs1(to[e]);
size[u] += size[to[e]];
if(size[to[e]] > size[son[u]]) son[u] = to[e];
}
}
IL void Dfs2(RG int u, RG int Top){
top[u] = Top; dfn[u] = ++cnt;
if(son[u]) Dfs2(son[u], Top);
for(RG int e = fst[u]; e != -1; e = nxt[e])
if(!dfn[to[e]]) Dfs2(to[e], to[e]);
}
IL void Update(RG int x){ sum[x] = (sum[x << 1] + sum[x << 1 | 1]) % MOD; }
IL void Pushdown(RG int x, RG int l, RG int r){
if(!tag[x]) return;
RG int mid = (l + r) >> 1, ls = x << 1, rs = x << 1 | 1;
(sum[ls] += (mid - l + 1) * tag[x]) %= MOD;
(sum[rs] += (r - mid) * tag[x]) %= MOD;
tag[ls] += tag[x]; tag[rs] += tag[x]; tag[x] = 0;
}
IL void Modify(RG int x, RG int l, RG int r, RG int L, RG int R){
if(L <= l && R >= r){
(sum[x] += r - l + 1) %= MOD; tag[x]++;
return;
}
Pushdown(x, l, r);
RG int mid = (l + r) >> 1;
if(L <= mid) Modify(x << 1, l, mid, L, R);
if(R > mid) Modify(x << 1 | 1, mid + 1, r, L, R);
Update(x);
}
IL int Query(RG int x, RG int l, RG int r, RG int L, RG int R){
if(L <= l && R >= r) return sum[x];
Pushdown(x, l, r);
RG int mid = (l + r) >> 1, Ans = 0;
if(L <= mid) Ans = Query(x << 1, l, mid, L, R);
if(R > mid) Ans += Query(x << 1 | 1, mid + 1, r, L, R);
Update(x);
return Ans;
}
IL void Cover(RG int x, RG int y){
while(top[x] != top[y]){
if(deep[top[x]] < deep[top[y]]) swap(x, y);
Modify(1, 1, n, dfn[top[x]], dfn[x]);
x = fa[top[x]];
}
if(deep[x] < deep[y]) swap(x, y);
Modify(1, 1, n, dfn[y], dfn[x]);
}
IL int Calc(RG int x, RG int y){
RG int Ans = 0;
while(top[x] != top[y]){
if(deep[top[x]] < deep[top[y]]) swap(x, y);
Ans += Query(1, 1, n, dfn[top[x]], dfn[x]);
x = fa[top[x]];
}
if(deep[x] < deep[y]) swap(x, y);
Ans += Query(1, 1, n, dfn[y], dfn[x]);
return Ans;
}
int main(RG int argc, RG char *argv[]){
n = Read(); q = Read(); Fill(fst, -1);
for(RG int i = 2, a; i <= n; ++i) a = Read() + 1, Add(a, i), Add(i, a);
Dfs1(1); cnt = 0; Dfs2(1, 1); cnt = 0;
for(RG int i = 1; i <= q; ++i){
qry[++cnt].f = Read(); qry[cnt].id = i; qry[cnt].type = -1;
qry[++cnt].f = Read() + 1; qry[cnt].id = i; qry[cnt].type = 1;
z[i] = Read() + 1;
}
sort(qry + 1, qry + cnt + 1);
for(RG int i = 1, j = 0; i <= cnt; ++i){
while(j < qry[i].f) ++j, Cover(1, j);
ans[qry[i].id] += qry[i].type * Calc(1, z[qry[i].id]);
}
for(RG int i = 1; i <= q; i++) printf("%d\n", (ans[i] % MOD + MOD) % MOD);
return 0;
}