#HYSBZ3626[LNOI2014]#LCA(经典模型:树剖+线段树维护和)

来源:互联网 发布:java记事本代码讲解 编辑:程序博客网 时间:2024/06/07 02:11

3626: [LNOI2014]LCA

Time Limit: 10 Sec  Memory Limit: 128 MB

Description

给出一个n个节点的有根树(编号为0到n-1,根节点为0)。一个点的深度定义为这个节点到根的距离+1。
设dep[i]表示点i的深度,LCA(i,j)表示i与j的最近公共祖先。
有q次询问,每次询问给出l r z,求sigma_{l<=i<=r}dep[LCA(i,z)]。
(即,求在[l,r]区间内的每个节点i与z的最近公共祖先的深度之和)

Input

第一行2个整数n q。
接下来n-1行,分别表示点1到点n-1的父节点编号。
接下来q行,每行3个整数l r z。

Output

输出q行,每行表示一个询问的答案。每个答案对201314取模输出

Sample Input

5 2
0
0
1
1
1 4 3
1 4 2

Sample Output

8
5

HINT

共5组数据,n与q的规模分别为10000,20000,30000,40000,50000。



很经典的树剖题,学会了一种新的方法。

预备一下做法:

对于要求的i, z的LCA的祖先深度,我们可以这样做,首先将从i到根的每个节点都+1,然后统计从z到根的和,和即为深度,如图:


离线询问,将一个询问区间拆成[1, l-1]和[1, r],那么[l, r]的和就变成了sum[1, r] - sum[1, l - 1]

将所有点按照轻重链先后dfs序重编号,那么重链上的点编号一定是连续的,一个点也是重链。

用重新编的号作为线段树的下标。

从1~N每个点暴力向根节点+1,然后每次就统计从z到根的和,就是当时的[1, i]的sum。

加的时候就是按着轻重链剖分的方法,一直tp到根,每一段重链可以直接按照新编号的下标直接在线段树上更新区间。

每次查询也是按着轻重链剖分的方法,一直tp到根,每次询问一段重链的和。

时间复杂度为Nlog^2 N


Code:


#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>#include<cmath>#include<algorithm>using namespace std;const int Max = 50000;const int MOD = 201314;struct node{    int pos, t, id, tg;    bool operator < (const node X)const{        return pos < X.pos;    }}Ask[(Max << 1) + 5];struct TREE{    int l, r, sum, ad, num;}Tr[(Max << 2) + 5];int N, Q, ecnt, POS;int fir[Max + 5], nxt[Max + 5], V[Max + 5], An[(Max << 1) + 5];int fa[Max + 5], sz[Max + 5], son[Max + 5], tp[Max + 5], Dep[Max + 5];int ID[Max + 5], P[Max + 5];void getint(int & num){    char c; int flg = 1;    num = 0;    while((c = getchar()) < '0' || c > '9') if(c == '-')    flg = -1;    while(c >= '0' && c <= '9'){    num = num * 10 + c - 48;    c = getchar(); }    num *= flg;}void addedge(int a, int b){    V[++ ecnt] = b, nxt[ecnt] = fir[a], fir[a] = ecnt;}void Dfs1(int u, int ff){    Dep[u] = Dep[ff] + 1;    sz[u] = 1;    for(int i = fir[u]; i; i = nxt[i]){        Dfs1(V[i], u), sz[u] += sz[V[i]];        if(sz[V[i]] > sz[son[u]])   son[u] = V[i];    }}void Dfs2(int u){    ID[u] = ++ POS;    P[POS] = u;    if(son[u]){        tp[son[u]] = tp[u];        Dfs2(son[u]);    }    for(int i = fir[u]; i; i = nxt[i])  if(V[i] != fa[u] && V[i] != son[u])        tp[V[i]] = V[i],        Dfs2(V[i]);}void Build(int i, int l, int r){    Tr[i].l = l, Tr[i].r = r, Tr[i].sum = Tr[i].ad = 0;    if(l == r){        Tr[i].num = P[l], Tr[i].sum = 0;        return ;    }    int mid = (l + r) >> 1;    Build(i << 1, l, mid);    Build(i << 1 | 1, mid + 1, r);    Tr[i].sum = (Tr[i << 1].sum + Tr[i << 1 | 1].sum) % MOD;}void pushdown(int i){    int lc = i << 1, rc = i << 1 | 1;    Tr[lc].ad = (Tr[lc].ad + Tr[i].ad) % MOD;    Tr[rc].ad = (Tr[rc].ad + Tr[i].ad) % MOD;    Tr[lc].sum = (Tr[lc].sum + 1ll*Tr[i].ad * (Tr[lc].r - Tr[lc].l + 1) % MOD) % MOD;    Tr[rc].sum = (Tr[rc].sum + 1ll*Tr[i].ad * (Tr[rc].r - Tr[rc].l + 1) % MOD) % MOD;    Tr[i].ad = 0;}void Add(int i, int L, int R){    if(L <= Tr[i].l && R >= Tr[i].r){        Tr[i].ad = (Tr[i].ad + 1) % MOD;        Tr[i].sum = (Tr[i].sum + Tr[i].r - Tr[i].l + 1) % MOD;        return ;    }    int mid = (Tr[i].l + Tr[i].r) >> 1;    if(Tr[i].ad)   pushdown(i);    if(L <= mid)    Add(i << 1, L, R);    if(R > mid) Add(i << 1 | 1, L, R);    Tr[i].sum = (Tr[i << 1].sum + Tr[i << 1 | 1].sum) % MOD;}int Query(int i, int L, int R){    if(L <= Tr[i].l && R >= Tr[i].r)    return Tr[i].sum;    if(Tr[i].ad)    pushdown(i);    int mid = (Tr[i].l + Tr[i].r) >> 1, rt = 0;    if(L <= mid)    rt = (rt + Query(i << 1, L, R)) % MOD;    if(R > mid)     rt = (rt + Query(i << 1 | 1, L, R)) % MOD;    Tr[i].sum = (Tr[i << 1].sum + Tr[i << 1 | 1].sum) % MOD;    return rt;}void Update(int u){    while(u){        Add(1, ID[tp[u]], ID[u]);        u = fa[tp[u]];    }}int Cal(int u){    int rt = 0;    while(u){        rt = (rt + Query(1, ID[tp[u]], ID[u])) % MOD;        u = fa[tp[u]];    }    return rt;}int main(){    getint(N), getint(Q);    for(int i = 2; i <= N; ++ i)        getint(fa[i]), ++ fa[i], addedge(fa[i], i);    Dfs1(1, 0);    tp[1] = 1;    Dfs2(1);    Build(1, 1, N);    int l, r, T = 0;    int R = 0;    for(int i = 1; i <= Q; ++ i){        getint(l), getint(r), getint(Ask[++ T].t);        ++ l, ++ r, ++ Ask[T].t;        Ask[T].pos = l - 1, Ask[T].id = i, Ask[T].tg = -1, ++ T;        Ask[T].t = Ask[T - 1].t, Ask[T].pos = r, Ask[T].id = i, Ask[T].tg = 1;        R = max(R, r);    }    sort(Ask + 1, Ask + 1 + T);    int p = 1;    for(int i = 1; i <= T; ){        while(p <= Ask[i].pos){            Update(p), ++ p;        }        int j;        for(j = i; j <= T && Ask[j].pos == Ask[i].pos; ++ j){            int tmp = Cal(Ask[j].t);            An[Ask[j].id] += Ask[j].tg * tmp ;        }        i = j;    }    for(int i = 1; i <= Q; ++ i)    printf("%d\n", (An[i] + MOD) % MOD);    return 0;}
/*

5 2
0
0
1
1
1 4 3
1 4 2


7 5
0 0 1 1 2 2
0 6 0
0 6 1
5 6 2
5 6 1
0 4 1
7
10
4
2
8

*/



原创粉丝点击