• [LNOI2014]LCA(树链剖分+线段树)


    题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=3626

    题解:看到LCA,我们可以直接想到这题的正解不是LCA!(LCA只能得20分,还要卡常)
    于是我们怎么做呢?
    考虑如何求Σdep[lca(i,z)](i∈[l,r]),由于不强制在线,我们不妨考虑离线……考虑每个lca贡献的答案。很显然z的lca在路径[1,z]上,所以我们可以把每一个lca到根的路径中所有点权值都加1,再从z跑一遍加上路径上的点的贡献即可。对于[l,r],可以枚举i,然后i~根路径+1,跑一遍就行了,但这样会TLE,怎么办?很显然就是把[l,r]视为[1,l-1]和[1,r]两部分,答案就是第二部分减去第一部分的值,然后只要开一个vector。从1~n扫一遍然后覆盖,对当前节点vector内的询问做一下query就行了

    #include<bits/stdc++.h>
    #define lson l,mid,rt*2
    #define rson mid+1,r,rt*2+1
    using namespace std;
    const int N=5e4+77,mod=201314;
    struct node{int id,v,z;};
    vector<node>S[N];
    vector<int>G[N];
    int n,q,cnt,fa[N],sz[N],dep[N],son[N],id[N],top[N],ans[N],sum[N*4],lazy[N*4];
    void dfs(int u)
    {
        sz[u]=1;
        for(int i=0;i<G[u].size();i++)
        {
            fa[G[u][i]]=u,dep[G[u][i]]=dep[u]+1;
            dfs(G[u][i]);
            sz[u]+=sz[G[u][i]];
            if(sz[son[u]]<sz[G[u][i]])son[u]=G[u][i];
        }
    }
    void dfs2(int u,int tp)
    {
        id[u]=++cnt,top[u]=tp;
        if(son[u])dfs2(son[u],tp);
        for(int i=0;i<G[u].size();i++)
        if(G[u][i]!=son[u])dfs2(G[u][i],G[u][i]);
    }
    void pushdown(int rt,int d)
    {
        if(lazy[rt])
        {
            sum[rt*2]=(sum[rt*2]+1ll*lazy[rt]*(d-d/2))%mod;
            sum[rt*2+1]=(sum[rt*2+1]+1ll*lazy[rt]*(d/2))%mod;
            lazy[rt*2]=(lazy[rt*2]+lazy[rt])%mod;
            lazy[rt*2+1]=(lazy[rt*2+1]+lazy[rt])%mod;
            lazy[rt]=0;
        }
    }
    void update(int L,int R,int l,int r,int rt)
    {
        if(L<=l&&r<=R){sum[rt]=(sum[rt]+r-l+1)%mod,lazy[rt]=(lazy[rt]+1)%mod;return;}
        pushdown(rt,r-l+1);
        int mid=(l+r)/2;
        if(L<=mid)update(L,R,lson);
        if(R>mid)update(L,R,rson);
        sum[rt]=(sum[rt*2]+sum[rt*2+1])%mod;
    }
    int query(int L,int R,int l,int r,int rt)
    {
        if(L<=l&&r<=R)return sum[rt];
        pushdown(rt,r-l+1);
        int mid=(l+r)/2,ret=0;
        if(L<=mid)ret+=query(L,R,lson);
        if(R>mid)ret+=query(L,R,rson);
        return ret%mod;
    }
    void Update(int x)
    {
        while(top[x]!=1)update(id[top[x]],id[x],1,n,1),x=fa[top[x]];
        update(id[1],id[x],1,n,1);
    }
    int Query(int x)
    {
        int ret=0;
        while(top[x]!=1)ret=(ret+query(id[top[x]],id[x],1,n,1))%mod,x=fa[top[x]];
        ret+=query(id[1],id[x],1,n,1);
        return ret%mod;
    }
    int main()
    {
        scanf("%d%d",&n,&q);
        for(int i=2,x;i<=n;i++)scanf("%d",&x),G[x+1].push_back(i);
        dfs(1),dfs2(1,1);
        for(int i=1,l,r,z;i<=q;i++)
        scanf("%d%d%d",&l,&r,&z),S[l].push_back((node){i,-1,z+1}),S[r+1].push_back((node){i,1,z+1});
        for(int i=1;i<=n;i++)
        {
            Update(i);
            node x;
            for(int j=0;j<S[i].size();j++)x=S[i][j],ans[x.id]=(ans[x.id]+x.v*Query(x.z)+mod)%mod;
        }
        for(int i=1;i<=q;i++)printf("%d
    ",ans[i]);
    }
    View Code
  • 相关阅读:
    带花树
    pxe+kickstart部署多个版本的Linux操作系统(上)---原理篇
    GO学习——安装编译(1)
    git学习——Github关联(2)
    你可能不知道的printf
    Linux中的文件查找技巧
    C语言入坑指南-被遗忘的初始化
    Linux常用命令-解压缩篇
    Linux常用命令-文本查看篇
    C语言的main函数到底该怎么写
  • 原文地址:https://www.cnblogs.com/hfctf0210/p/10187947.html
Copyright © 2020-2023  润新知