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;
}

 

posted @ 2019-02-02 10:09  MJT12044  阅读(122)  评论(0编辑  收藏  举报