• LNOI2014 LCA


    LNOI2016 LCA

    好题啊qaq

    就是主席树的区间修改啊

    蛤?不会主席树区间修改?我也不会qaq

    好像不太容易进行pushdown操作

    但是有一个好东西叫做标记永久化啊!

    于是学习一波姿势  :

    https://www.cnblogs.com/Hallmeow/p/8004676.html

    https://www.cnblogs.com/wozaixuexi/p/9462461.html

    假设每个节点维护一个sum和add

    核心思想就是修改的时候沿途修改经过的节点的sum

    当修改区间与当前区间完全重合时更新add标记

    查询的时候沿途累加add标记,返回sum+add*len的和

    求(u,v)的 LCA 的一个技巧是将u到根节点的路径打上标记,查询v到根节点的和,显然树剖+线段树嘛(当然更可以LCT啦)

    这题其实可以询问离线,把(l,r) 的询问拆成 (1,l-1) 和 (1,r) ,这样可以按时间顺序向线段树中插入节点

    但这题还有一个加强版:HNOI2015开店  强制在线

    那怎么办啊qaq

    主席树嘛,区间修改的主席树嘛,于是这道题我也是这么写的

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<iostream>
    #include<cmath>
    #include<stack>
    #include<queue>
    using namespace std;
    typedef long long ll;
    
    const int maxn = 100100;
    const int mod = 201314;
    
    int n,q;
    
    int h[maxn],size;
    struct E{
        int to,next;
    }e[maxn];
    void add_edge(int u,int v){
        e[++size].to=v;
        e[size].next=h[u];
        h[u]=size;
    }
    
    int rt[maxn],lc[maxn*150],rc[maxn*150],sum[maxn*150],add[maxn*150],tot;
    
    int fa[maxn],dep[maxn],sz[maxn],son[maxn];
    int dfn[maxn],top[maxn],id[maxn],tim;
    
    void dfs1(int u,int par){
        fa[u]=par; dep[u]=dep[par]+1; sz[u]=1;
        int maxs=-1;
        for(int i=h[u];i!=-1;i=e[i].next){
            int v=e[i].to;
            if(v==par) continue;
            dfs1(v,u);
            sz[u]+=sz[v];
            if(sz[v]>maxs){
                maxs=sz[v];
                son[u]=v;
            }
        }
    }
    
    void dfs2(int u,int par){
        top[u]=par; dfn[u]=++tim; id[tim]=u;
        if(son[u]) dfs2(son[u],par);
        for(int i=h[u];i!=-1;i=e[i].next){
            int v=e[i].to;
            if(v==fa[u]||v==son[u]) continue;
            dfs2(v,v);
        }
    }
    
    void build(int &i,int l,int r){
        i=++tot;
        if(l==r) return;
        int mid=(l+r)/2;
        build(lc[i],l,mid);
        build(rc[i],mid+1,r);
    }
    
    void mdf(int &i,int l,int r,int x,int y){
        sum[++tot]=sum[i],lc[tot]=lc[i],rc[tot]=rc[i],add[tot]=add[i];
        i=tot;
        sum[i]+=(y-x+1); sum[i]%=mod;
        if(x==l&&r==y){ ++add[i]; return; }
        int mid=(l+r)/2;
        if(x>mid) mdf(rc[i],mid+1,r,x,y);
        else if(y<=mid) mdf(lc[i],l,mid,x,y);
        else{
            mdf(lc[i],l,mid,x,mid);
            mdf(rc[i],mid+1,r,mid+1,y);
        }
    }
    
    int qry(int i,int ad,int l,int r,int x,int y){
        if(l==x&&r==y){     return (sum[i]+1ll*ad*(r-l+1)%mod)%mod; }
        int mid=(l+r)/2;
        if(x>mid) return qry(rc[i],(ad+add[i])%mod,mid+1,r,x,y);
        else if(y<=mid) return qry(lc[i],(ad+add[i])%mod,l,mid,x,y);
        else{ return qry(lc[i],(ad+add[i])%mod,l,mid,x,mid)+qry(rc[i],ad+add[i],mid+1,r,mid+1,y); }
    }
    
    void upd(int i,int u,int v){
        while(top[u]^top[v]){
            if(dep[u]<dep[v]) swap(u,v);
            mdf(rt[i],1,n,dfn[top[u]],dfn[u]);
            u=fa[top[u]];
        }
        if(dep[u]>dep[v]) swap(u,v);
        mdf(rt[i],1,n,dfn[u],dfn[v]);
    }
    
    int query(int i,int u,int v){
        int res=0;
        while(top[u]^top[v]){
            if(dep[u]<dep[v]) swap(u,v);
            res+=qry(rt[i],0,1,n,dfn[top[u]],dfn[u]); res%=mod;
            u=fa[top[u]];
        }
        if(dep[u]>dep[v]) swap(u,v);
        res+=qry(rt[i],0,1,n,dfn[u],dfn[v]); res%=mod;
        return res;
    }
    
    ll read(){ ll s=0,f=1; char ch=getchar(); while(ch<'0' || ch>'9'){ if(ch=='-') f=-1; ch=getchar(); } while(ch>='0' && ch<='9'){ s=s*10+ch-'0'; ch=getchar(); } return s*f; }
    
    int main(){
        memset(h,-1,sizeof(h));
        n=read(),q=read();
        int u,v,z;
        for(int i=2;i<=n;i++){
            u=read(); ++u;
            add_edge(i,u),add_edge(u,i);
        }
        
        dfs1(1,0); dfs2(1,1);
        build(rt[0],1,n);
        for(int i=1;i<=n;i++){ rt[i]=rt[i-1]; upd(i,1,i); }
        
        for(int i=1;i<=q;i++){
            u=read()+1,v=read()+1,z=read()+1;
            printf("%d\n",(query(v,1,z)-query(u-1,1,z)+mod)%mod);
        }
        return 0;
    }
  • 相关阅读:
    关于PDF.NET开发框架对Mysql Sqlite PostgreSQL数据库分页支持的个人看法
    【山外转载】如何高效的学习技术
    【山外笔记-四级计算机网络】第1章 网络技术基础
    【山外笔记-云原生】《Docker+Kubernetes应用开发与快速上云》读书笔记-2020.04.25(六)
    【山外笔记-数据库】Memcached教程详解
    【山外问道】什么是UUID
    【山外问道】Linux UUID的查询方法
    【山外笔记-SVN命令】svnlook命令详解
    【山外笔记-SVN命令】svn命令详解
    【山外笔记-工具框架】SVN版本控制系统
  • 原文地址:https://www.cnblogs.com/tuchen/p/10545077.html
Copyright © 2020-2023  润新知