P4211 [LNOI2014]LCA
P4211 [LNOI2014]LCA
分析:
首先一种比较有趣的转化是,将所有点到1的路径上都+1,然后z到1的路径上的和,就是所有答案的deep的和。
对于多次询问,要么考虑有把询问离线,省去每次询问的复杂度,多个一起处理,要么做到优化掉查询。
这里发现求deep和的过程不能在省了,于是可以差分询问,枚举右端点,然后查询所有1到这个点的和。
而第一步的操作可以树链剖分完成。(并且查询的是一个区间,这也保证了这样做可行)
复杂度$O(nlog^2n)$
代码:
#include<cstdio> #include<algorithm> #include<cstring> #include<iostream> #include<cmath> #include<cctype> #include<set> #include<queue> #include<vector> #include<map> #define pa pair<int,int> using namespace std; typedef long long LL; inline int read() { int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1; for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f; } const int N = 100005, mod = 201314; struct Edge{ int to, nxt; } e[N << 1]; int head[N], sum[N << 2], tag[N << 2], fa[N], siz[N], son[N], bel[N], xl[N], ans[N]; int En, Index, n; vector< pa > Que[N]; inline void add_edge(int u,int v) { ++En; e[En].to = v, e[En].nxt = head[u]; head[u] = En; } inline void pushdown(int rt,int len) { sum[rt << 1] += (len - (len / 2)) * tag[rt]; sum[rt << 1 | 1] += (len / 2) * tag[rt]; tag[rt << 1] += tag[rt]; tag[rt << 1 | 1] += tag[rt]; tag[rt] = 0; } void update(int l,int r,int rt,int L,int R) { if (L <= l && r <= R) { tag[rt] ++; (sum[rt] += r - l + 1) %= mod; return ; } if (tag[rt]) pushdown(rt, r - l + 1); int mid = (l + r) >> 1; if (L <= mid) update(l, mid, rt << 1, L, R); if (R > mid) update(mid + 1, r, rt << 1 | 1, L, R); sum[rt] = (sum[rt << 1] + sum[rt << 1 | 1]) % mod; } int query(int l,int r,int rt,int L,int R) { if (L <= l && r <= R) return sum[rt]; if (tag[rt]) pushdown(rt, r - l + 1); int mid = (l + r) >> 1, res = 0; if (L <= mid) res = (res + query(l, mid, rt << 1, L, R)) % mod; if (R > mid) res = (res + query(mid + 1, r, rt << 1 | 1, L, R)) % mod; return res; } void dfs1(int u) { siz[u] = 1; for (int i = head[u]; i; i = e[i].nxt) { int v = e[i].to; dfs1(v); siz[u] += siz[v]; if (!son[u] || siz[son[u]] < siz[v]) son[u] = v; } } void dfs2(int u,int top) { bel[u] = top; xl[u] = ++Index; if (!son[u]) return ; dfs2(son[u], top); for (int i = head[u]; i; i = e[i].nxt) if (e[i].to != son[u]) dfs2(e[i].to, e[i].to); } void add(int x) { while (x) { update(1, n, 1, xl[bel[x]], xl[x]); x = fa[bel[x]]; } } int query(int x) { int ans = 0; while (x) { ans = (ans + query(1, n, 1, xl[bel[x]], xl[x])) % mod; x = fa[bel[x]]; } return ans; } int main() { n = read();int m = read(); for (int i = 2; i <= n; ++i) { fa[i] = read() + 1; add_edge(fa[i], i); } dfs1(1); dfs2(1, 1); for (int i = 1; i <= m; ++i) { int l = read() + 1, r = read() + 1, z = read() + 1; Que[r].push_back(pa(z, i)); Que[l - 1].push_back(pa(z, -i)); } for (int i = 1; i <= n; ++i) { add(i); for (int sz = Que[i].size(), j = 0; j < sz; ++j) { if (Que[i][j].second < 0) ans[-Que[i][j].second] -= query(Que[i][j].first); else ans[Que[i][j].second] += query(Que[i][j].first); } } for (int i = 1; i <= m; ++i) printf("%d\n", (ans[i] + mod) % mod); return 0; }