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;
}
posted @ 2017-12-31 20:26  Cyhlnj  阅读(166)  评论(0编辑  收藏  举报