• [Luogu] LCA


    https://www.luogu.org/problemnew/show/P4211

    baoli

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    
    using namespace std;
    const int N = 5e4 + 10;
    const int Mod = 201314;
    
    #define gc getchar()
    
    #define RR freopen("gg.in", "r", stdin) 
    
    int fa[N] = {-1}, deep[N], cnt[N], head[N]; 
    struct Node {int u, v, nxt;} G[N];
    int n, Ty, now = 1;
    
    inline int read() {
        int x = 0; char c = gc;
        while(c < '0' || c > '9') c = gc;
        while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = gc;
        return x;
    }
    
    inline void Add(int u, int v) {
        G[now].u = u; G[now].v = v; G[now].nxt = head[u]; head[u] = now ++;
    }
    
    void Dfs(int u, int dep) {
        deep[u] = dep;
        for(int i = head[u]; ~ i; i = G[i].nxt) {
            int v = G[i].v;
            if(v != fa[u]) Dfs(v, dep + 1);
        }
    }
    
    void Dfs_2(int u) {
        if(head[u] == -1) return ;
        for(int i = head[u]; ~ i; i = G[i].nxt) {
            int v = G[i].v;
            if(v != fa[u]) {
                Dfs_2(v);
                cnt[u] += cnt[v];
            }
        }
    }
    
    int main() {
        n = read();
        Ty = read();
        for(int i = 0; i < n; i ++) head[i] = -1;
        for(int i = 1; i < n; i ++) {
            int u = read(); fa[i] = u;
            Add(u, i); Add(i, u);
        }
        Dfs(0, 1);
        while(Ty --) {
            int l = read(); int r = read(); int z = read();
            for(int i = l; i <= r; i ++) cnt[i] ++;
            Dfs_2(0);
            int imp = z;
            int Answer = 0;
            while(fa[imp] != -1) {
                Answer += cnt[imp];
                Answer %= Mod;
                imp = fa[imp];
            } Answer += cnt[imp];
            Answer %= Mod;
            cout << Answer << endl;
            memset(cnt, 0, sizeof cnt);
        }
        return 0;
    } 

    考虑这样的等价问题,如果我们把一个点 x 到 Root 的路径上每个点的权值赋为 1 ,其余点的权值为 0,那么从 LCA(x, y) 的 Depth 就是从 y 到 Root 的路径上的点权和。

    这个方法是可以叠加的,这是非常有用的一点。如果我们把 [l, r] 的每个点到 Root 的路径上所有点的权值 +1,再求出从 c 到 Root 的路径点权和,即为 [l, r] 中所有点与 c 的 LCA 的 Depth 和。

    不仅满足可加性,还满足可减性,这就更好了!

    那么我们就可以对每个询问 [l, r] 做一个差分,用 Query(r) - Query(l - 1) 作为答案。这样就有一种离线算法:将 n 个点依次操作,将其到 Root 的路径上的点权值 +1 ,然后如果这个点是某个询问的 l - 1 或 r ,就用那个询问的 c 求一下到 Root 的路径和,算入答案中。

    #include<cmath>
    #include<ctime>
    #include<queue>
    #include<stack>
    #include<cstdio>
    #include<vector>
    #include<cstring>
    #include<cstdlib>
    #include<iostream>
    #include<algorithm>
    #define N 50005
    #define M 201314
    #define K 150005
    using namespace std;
    struct graph {
        int nxt,to;
    } e[N];
    struct quest {
        int x,z,n,ans;
    } l[N],r[N];
    struct linetree {
        int l,r,s,len,lzy;
    } lt[K];
    int g[N],n,q,t1,t2,cnt;
    int f[N],p[N],dep[N],top[N],siz[N],son[N];
    inline int read() {
        int ret=0;
        char c=getchar();
        while(!isdigit(c))
            c=getchar();
        while(isdigit(c)) {
            ret=(ret<<1)+(ret<<3)+c-'0';
            c=getchar();
        }
        return ret;
    }
    inline void addedge(int x,int y) {
        e[++cnt].nxt=g[x];
        g[x]=cnt;
        e[cnt].to=y;
    }
    inline void dfs1(int u) {
        int m=0;
        siz[u]=1;
        for(int i=g[u]; i; i=e[i].nxt) {
            f[e[i].to]=u;
            dep[e[i].to]=dep[u]+1;
            dfs1(e[i].to);
            siz[u]+=siz[e[i].to];
            if(siz[e[i].to]>m) {
                son[u]=e[i].to;
                m=siz[e[i].to];
            }
        }
    }
    inline void dfs2(int u,int tp) {
        top[u]=tp;
        p[u]=++cnt;
        if(son[u]) dfs2(son[u],tp);
        for(int i=g[u]; i; i=e[i].nxt)
            if(e[i].to!=son[u])
                dfs2(e[i].to,e[i].to);
    }
    inline void build(int u,int l,int r) {
        lt[u].l=l;
        lt[u].r=r;
        lt[u].len=lt[u].r-lt[u].l+1;
        if(lt[u].l<lt[u].r) {
            int lef=u<<1,rig=u<<1|1;
            int mid=lt[u].l+lt[u].r>>1;
            build(lef,l,mid);
            build(rig,mid+1,r);
        }
    }
    inline int cover(int u,int l,int r) {
        if(lt[u].l>=l&&lt[u].r<=r) {
            ++lt[u].lzy;
            lt[u].s=(lt[u].s+lt[u].len)%M;
        } else if(lt[u].l<lt[u].r) {
            int lef=u<<1,rig=u<<1|1;
            int mid=lt[u].l+lt[u].r>>1;
            if(lt[u].lzy) {
                lt[lef].lzy+=lt[u].lzy;
                lt[rig].lzy+=lt[u].lzy;
                lt[lef].s=(lt[lef].s+lt[lef].len*lt[u].lzy)%M;
                lt[rig].s=(lt[rig].s+lt[rig].len*lt[u].lzy)%M;
                lt[u].lzy=0;
            }
            if(l<=mid) cover(lef,l,r);
            if(r>mid) cover(rig,l,r);
            lt[u].s=(lt[lef].s+lt[rig].s)%M;
        }
    }
    inline int ask(int u,int l,int r) {
        if(lt[u].l>=l&&lt[u].r<=r)
            return lt[u].s;
        if(lt[u].l<lt[u].r) {
            int lef=u<<1,rig=u<<1|1,ret=0;
            int mid=lt[u].l+lt[u].r>>1;
            if(lt[u].lzy) {
                lt[lef].lzy+=lt[u].lzy;
                lt[rig].lzy+=lt[u].lzy;
                lt[lef].s=(lt[lef].s+lt[lef].len*lt[u].lzy)%M;
                lt[rig].s=(lt[rig].s+lt[rig].len*lt[u].lzy)%M;
                lt[u].lzy=0;
            }
            if(l<=mid) ret=(ret+ask(lef,l,r))%M;
            if(r>mid) ret=(ret+ask(rig,l,r))%M;
            return ret;
        }
    }
    inline void add(int x,int y) {
        int t;
        while(top[x]!=top[y]) {
            if(dep[top[x]]<dep[top[y]]) {
                t=x;
                x=y;
                y=t;
            }
            cover(1,p[top[x]],p[x]);
            x=f[top[x]];
        }
        if(p[x]>p[y]) {
            t=x;
            x=y;
            y=t;
        }
        cover(1,p[x],p[y]);
    }
    inline int que(int x,int y) {
        int ret=0,t;
        while(top[x]!=top[y]) {
            if(dep[top[x]]<dep[top[y]]) {
                t=x;
                x=y;
                y=t;
            }
            ret=(ret+ask(1,p[top[x]],p[x]))%M;
            x=f[top[x]];
        }
        if(p[x]>p[y]) {
            t=x;
            x=y;
            y=t;
        }
        ret=(ret+ask(1,p[x],p[y]))%M;
        return ret;
    }
    inline bool cmp1(quest x,quest y) {
        return x.x<y.x;
    }
    
    inline bool cmp2(quest x,quest y) {
        return x.n<y.n;
    }
    inline void Aireen() {
        n=read();
        q=read();
        for(int i=2,j; i<=n; ++i) {
            j=read()+1;
            addedge(j,i);
        }
        for(int i=1; i<=q; ++i) {
            l[i].n=r[i].n=i;
            l[i].x=read();
            r[i].x=read()+1;
            l[i].z=r[i].z=read()+1;
        }
        sort(l+1,l+1+q,cmp1);
        sort(r+1,r+1+q,cmp1);
        while(t1<=q&&!l[t1].x) ++t1;
        while(t2<=q&&!r[t2].x) ++t2;
        dep[1]=1;
        dfs1(1);
        cnt=0;
        dfs2(1,1);
        build(1,1,n);
        for(int i=1; i<=n; ++i) {
            add(1,i);
            while(t1<=q&&l[t1].x==i) {
                l[t1].ans=que(1,l[t1].z);
                ++t1;
            }
            while(t2<=q&&r[t2].x==i) {
                r[t2].ans=que(1,r[t2].z);
                ++t2;
            }
        }
        sort(l+1,l+1+q,cmp2);
        sort(r+1,r+1+q,cmp2);
        for(int i=1; i<=q; ++i)
            printf("%d
    ",(r[i].ans-l[i].ans+M)%M);
    }
    int main() {
        Aireen();
        fclose(stdin);
        fclose(stdout);
        return 0;
    }
  • 相关阅读:
    perl 实现ascall 码转换
    perl 利用管道读取压缩文件内容
    perl 字符串比较操作符
    perl chomp 函数的真正作用
    RSQLite 操作sqlite数据库
    R 中的do.call 函数
    JavaMail发送和接收邮件API(详解)
    POP3_使用SSL链接邮箱并获取邮件
    MySql_delete同时删除多表相关联记录
    mybatis_mybatis写mapper文件注意事项
  • 原文地址:https://www.cnblogs.com/shandongs1/p/8455762.html
Copyright © 2020-2023  润新知