• P4211 [LNOI2014]LCA


    Problem

    给一棵(n)个节点的有根树,(m)次询问,每次询问给(l,r,z),求(sum_{i = l}^r dep[LCA(i,z)])
    (1 le n,m le 500000)

    Solution

    Thinking 1

    我会暴力!
    树剖LCA,(mathcal{O}(nlog{n} + nq))属于是。
    你要树剖LCA不会只会倍增的话那还得加个(log{n}cdot q)

    Thinking 2

    我会找性质!
    发现对于任意两点(x,y),询问(dep[LCA(x,y)])其实就是等同于:
    在根节点到(x)的链上加1
    (y)到根节点的和
    那么对于多组询问(x in [l,r]),我们可以把(l sim r)的所有点到根节点都先加1,然后从(z)到根跑一遍即得(sum_{i = l} ^ r dep[LCA(i,z)])
    树剖搞搞就行。

    Thinking 3

    我是离线人!
    把所有询问({l,r,z})拆成({l - 1,z,-1})({r,z,1})
    然后按照首排序。
    我们把所有点到根节点顺着加一遍,然后中间询问处理一下。这样复杂度非常优秀!

    # include <bits/stdc++.h>
    using namespace std;
    const int N = 5e4 + 5,mod = 201314;
    int n,m;
    vector <int> g[N];
    int f[N],dep[N];
    int dfn[N],siz[N],top[N],son[N],dfntot = 0;
    int Ans[N];
    struct node
    {
        int val,lazy;
    }T[N << 2];
    struct Query
    {
        int x,z,opt;
        int answer,id;
        Query() {}
        Query(int _x,int _z,int _opt,int _id) : x(_x),z(_z),opt(_opt),id(_id) {}
    }Q[N << 1];
    bool compare(const struct Query &x, const struct Query &y)
    {
        return x.x < y.x;
    }
    int Hash[N][2];
    void dfs1(int x)
    {
        siz[x] = 1;
        for(int i = 0; i < (int)g[x].size(); i++)
        {
            int v = g[x][i];
            if(!dep[v]) 
            {
                dep[v] = dep[x] + 1;
                f[v] = x;
                dfs1(v);
                siz[x] += siz[v];
                if(siz[v] > siz[son[x]]) son[x] = v;
            }
        }
        return;
    }  
    void dfs2(int x,int _top)
    {
        top[x] = _top;
        dfn[x] = ++dfntot;
        if(son[x]) dfs2(son[x],_top);
        for(int i = 0; i < (int)g[x].size(); i++)
        {
            int v = g[x][i];
            if(v != f[x] && v != son[x]) 
            {
                dfs2(v,v);
            }
        }
        return;
    }
    void pushdown(int root,int l,int r)
    {
        if(T[root].lazy == 0) return;
        int tag = T[root].lazy,mid = (l + r) >> 1;
        T[root << 1].val = (T[root << 1].val + tag * (mid - l + 1)) % mod;
        T[root << 1 | 1].val = (T[root << 1 | 1].val + tag * (r - mid)) % mod;
        T[root << 1].lazy = (T[root << 1].lazy + tag) % mod;
        T[root << 1 | 1].lazy = (T[root << 1 | 1].lazy + tag) % mod;
        T[root].lazy = 0;
        return;
    }
    void update(int root,int l,int r,int s,int t,int d)
    {
        if(l <= s && t <= r)
        {
            T[root].val = (T[root].val + d * (t - s + 1)) % mod;
            T[root].lazy = (T[root].lazy + d) % mod;
            return;
        }
        pushdown(root,s,t);
        int mid = (s + t) >> 1;
        if(l <= mid) update(root << 1,l,r,s,mid,d);
        if(r > mid) update(root << 1 | 1,l,r,mid + 1,t,d);
        T[root].val = (T[root << 1].val + T[root << 1 | 1].val) % mod;
        return;
    }
    int query(int root,int l,int r,int s,int t)
    {
        if(l <= s && t <= r) return T[root].val % mod;
        pushdown(root,s,t);
        int mid = (s + t) >> 1;
        int ans = 0;
        if(l <= mid) ans = (ans + query(root << 1,l,r,s,mid)) % mod;
        if(r > mid) ans = (ans + query(root << 1 | 1,l,r,mid + 1,t)) % mod;
        return ans % mod;
    }
    void modify(int x,int y,int d = 1) // add link(x,y) to 1
    {
        while(top[x] != top[y])
        {
            if(dep[top[x]] > dep[top[y]])
                swap(x,y);
            update(1,dfn[top[y]],dfn[y],1,dfntot,d);
            y = f[top[y]];
        }
        if(dep[x] > dep[y]) swap(x,y);
        update(1,dfn[x],dfn[y],1,dfntot,d);
        return;
    }
    int q(int x,int y)
    {
        int ans = 0;
        while(dep[top[x]] != dep[top[y]])
        {
            if(dep[top[x]] > dep[top[y]]) 
                swap(x,y);
            ans = (ans + query(1,dfn[top[y]],dfn[y],1,dfntot)) % mod;
            y = f[top[y]];
        }
        if(dep[x] > dep[y]) swap(x,y);
        ans = (ans + query(1,dfn[x],dfn[y],1,dfntot)) % mod;
        return ans;
    }
    int main(void)
    {
        scanf("%d%d",&n,&m);
        for(int i = 2; i <= n; i++)
        {
            int v; scanf("%d",&v);
            ++v;
            g[i].push_back(v),g[v].push_back(i);
        }
        dep[1] = 1;
        dfs1(1),dfs2(1,1);
        for(int i = 1; i <= m; i++)
        {
            int l,r,z; scanf("%d%d%d",&l,&r,&z); ++l,++r,++z;
            Q[i * 2 - 1] = Query(l - 1,z,-1,i);
            Q[i * 2] = Query(r,z,1,i);
            Hash[l - 1][0] = i * 2 - 1,Hash[r][1] = i * 2;
        }
        sort(Q + 1, Q + 2 * m + 1, compare);
        for(int i = 1,j = 1; i <= 2 * m; i++)
        {
            while(j <= n && j <= Q[i].x)
            {
                modify(1,j);
                ++j;
            }
            Q[i].answer = q(1,Q[i].z);
            // printf("i = %d,x = %d,z = %d,answer = %d
    ",i,Q[i].x,Q[i].z,Q[i].answer);
        }
        for(int i = 1; i <= 2 * m; i++)
        {
            Ans[Q[i].id] = (Ans[Q[i].id] + Q[i].opt * Q[i].answer + mod) % mod;
        }
        for(int i = 1; i <= m; i++) printf("%d
    ",Ans[i]);
        return 0;
    }
    
  • 相关阅读:
    毕业季,致青春
    java判断是什么操作系统
    Error assembling WAR: webxml attribute is required (or preexisting WEBINF/web.xml if executing in update mode)
    MySQL截取字符串
    java.lang.NoClassDefFoundError: net/sf/jsqlparser/expression/Expression
    SpringBoot 配置文件敏感信息加密
    SpringBoot下载Excel文件无法打开
    SpringBoot引入SDK及打包
    文件与base64如何互转?
    InputStream类available和read方法读取流数据不全?
  • 原文地址:https://www.cnblogs.com/luyiming123blog/p/15112686.html
Copyright © 2020-2023  润新知