zoukankan      html  css  js  c++  java
  • 轻重链剖分

    重链剖分

    P3384 【模板】轻重链剖分/树链剖分 $ / $ 模板代码:

    注意:

    • 如果有 (0) 号节点,并默认重儿子是零号节点,复杂度会退化为 (O(n^2)) 。原因:

      • 代码第一次遍历默认重儿子是0,所以无法保证每次找到重儿子。如果重儿子的节点数小于根节点,那么重儿子不会被记录。

      • 而在第二次遍历中,因为应该被找到的重儿子没被找到,所以少了重边。

      • 由于少了很多重链,本来可以一次跳到重链顶的转移必须沿着轻链条很多次,时间复杂度就上去了,由 (O(n log n)) 退化为 (O(n^2))

        • 解决方法:将每一个节点编号都加一 。
    #include<bits/stdc++.h>
    using namespace std;
    #define Maxn 100005
    typedef long long ll;
    inline int rd()
    {
    	 int x=0;
         char ch,t=0;
         while(!isdigit(ch = getchar())) t|=ch=='-';
         while(isdigit(ch)) x=x*10+(ch^48),ch=getchar();
         return x=t?-x:x;
    }
    int n,m,root,mod,tot=1,N;
    int val[Maxn],fa[Maxn],siz[Maxn],Bigson[Maxn];
    int tp[Maxn],dep[Maxn],dfnl[Maxn],dfnr[Maxn],reg[Maxn]; // reg !!dfn是线段树上的节点号,与所对应的真实节点号不同 
    int hea[Maxn],ver[Maxn*2],nex[Maxn*2];
    struct TREE { int sum,laz; }tree[Maxn<<2];
    void add_edge(int x,int y) { ver[++tot]=y,nex[tot]=hea[x],hea[x]=tot; }
    void dfs1(int x)
    {
    	 siz[x]=1;
    	 for(int i=hea[x];i;i=nex[i])
    	 {
    	 	 if(ver[i]==fa[x]) continue;
    	 	 dep[ver[i]]=dep[x]+1,fa[ver[i]]=x;
    	 	 dfs1(ver[i]);
    	 	 siz[x]+=siz[ver[i]];
    	 	 if(siz[ver[i]]>siz[Bigson[x]]) Bigson[x]=ver[i];
    	 }
    }
    void dfs2(int x,int T)
    {
    	 tp[x]=T,dfnl[x]=++N,reg[N]=x;
    	 if(Bigson[x]) dfs2(Bigson[x],T);
    	 for(int i=hea[x];i;i=nex[i])
    	 {
    	 	 if(ver[i]==fa[x] || ver[i]==Bigson[x]) continue;
    	 	 dfs2(ver[i],ver[i]);
    	 }
    	 dfnr[x]=N;
    }
    void pushdown(int p,int nl,int nr)
    {
    	 if(tree[p].laz)
    	 {
    	 	 int mid=(nl+nr)>>1;
    	 	 tree[p<<1].sum=(tree[p<<1].sum+tree[p].laz*(mid-nl+1))%mod;
    	 	 tree[p<<1|1].sum=(tree[p<<1|1].sum+tree[p].laz*(nr-mid))%mod;
    	 	 tree[p<<1].laz=(tree[p<<1].laz+tree[p].laz)%mod;
    	 	 tree[p<<1|1].laz=(tree[p<<1|1].laz+tree[p].laz)%mod;
    	 	 tree[p].laz=0;
    	 }
    }
    void build(int p,int nl,int nr)
    {
    	 if(nl==nr) { tree[p].sum=val[reg[nl]]; return; }
    	 int mid=(nl+nr)>>1;
    	 build(p<<1,nl,mid),build(p<<1|1,mid+1,nr);
    	 tree[p].sum=(tree[p<<1].sum+tree[p<<1|1].sum)%mod;
    }
    void add(int p,int nl,int nr,int l,int r,int k)
    {
    	 if(nl>=l && nr<=r)
    	 {
    	 	 tree[p].sum=(tree[p].sum+k*(nr-nl+1))%mod;
    	 	 tree[p].laz+=k;
    	 	 return;
    	 }
    	 pushdown(p,nl,nr);
    	 int mid=(nl+nr)>>1;
    	 if(mid>=l) add(p<<1,nl,mid,l,r,k);
    	 if(mid<r) add(p<<1|1,mid+1,nr,l,r,k);
    	 tree[p].sum=(tree[p<<1].sum+tree[p<<1|1].sum)%mod;
    }
    int query(int p,int nl,int nr,int l,int r)
    {
    	 if(nl>=l && nr<=r) return tree[p].sum;
    	 pushdown(p,nl,nr);
    	 int mid=(nl+nr)>>1,ret=0;
    	 if(mid>=l) ret=query(p<<1,nl,mid,l,r);
    	 if(mid<r) ret+=query(p<<1|1,mid+1,nr,l,r);
    	 tree[p].sum=(tree[p<<1].sum+tree[p<<1|1].sum)%mod;
    	 return ret%mod;
    }
    void add_path(int x,int y,int k) // 注意:这道题的权重在 点 上 
    {
    	 while(tp[x]!=tp[y])
    	 {
    	 	 if(dep[tp[x]]<dep[tp[y]]) swap(x,y);
    	 	 add(1,1,n,dfnl[tp[x]],dfnl[x],k);
    	 	 x=fa[tp[x]];
    	 }
    	 if(dep[x]<dep[y]) swap(x,y);
    	 add(1,1,n,dfnl[y],dfnl[x],k);
    }
    int query_path(int x,int y)
    {
    	 int ret=0;
    	 while(tp[x]!=tp[y])
    	 {
    	 	 if(dep[tp[x]]<dep[tp[y]]) swap(x,y);
    	 	 ret=(ret+query(1,1,n,dfnl[tp[x]],dfnl[x]))%mod;
    	 	 x=fa[tp[x]];
    	 }
    	 if(dep[x]<dep[y]) swap(x,y);
    	 ret=(ret+query(1,1,n,dfnl[y],dfnl[x]))%mod;
    	 return ret;
    }
    int main()
    {
         //freopen(".in","r",stdin);
         //freopen(".out","w",stdout);
    	 n=rd(),m=rd(),root=rd(),mod=rd();
    	 for(int i=1;i<=n;i++) val[i]=rd();
    	 for(int i=1,u,v;i<n;i++) u=rd(),v=rd(),add_edge(u,v),add_edge(v,u);
    	 dfs1(root),dfs2(root,root),build(1,1,n);
    	 for(int i=1,opt,x,y,z;i<=m;i++)
    	 {
    	 	 opt=rd();
    	 	 if(opt==1) x=rd(),y=rd(),z=rd()%mod,add_path(x,y,z);
    		 else if(opt==2) x=rd(),y=rd(),printf("%d
    ",query_path(x,y));
    		 else if(opt==3) x=rd(),z=rd(),add(1,1,n,dfnl[x],dfnr[x],z);
    		 else x=rd(),printf("%d
    ",query(1,1,n,dfnl[x],dfnr[x]));
    	 }
         //fclose(stdin);
         //fclose(stdout);
         return 0;
    }
    
  • 相关阅读:
    Live2D 看板娘
    Live2D 看板娘
    Live2D 看板娘
    Live2D 看板娘
    Live2D 看板娘
    Live2D 看板娘
    [并发编程]并发编程第一篇:利用并发编程,实现查找大量数据中的素数
    [转载]Java数组扩容算法及Java对它的应用
    MineCraft note
    Hibernate一对一、一对多、多对多注解映射配置
  • 原文地址:https://www.cnblogs.com/EricQian/p/15067109.html
Copyright © 2011-2022 走看看