zoukankan      html  css  js  c++  java
  • 树链剖分

    树链剖分——轻重链剖分

    blog

    https://blog.csdn.net/qq_40482358/article/details/89676297

    树上的问题转化成序列问题(然后就快乐线段树维护)

    概括一下就是把树划分为若干条链,然后一个链的dfs序是连续的,对于树上两点,我们可以通过跳链直到两者在同一条链上,然后链上的权值就是区间问题

    定义:

    重儿子:所有儿子中子树(siz)最大的点,其他的都叫轻儿子

    重链:所有重儿子穿成的(许多条)链,其他的都叫轻链

    1

    性质:

    1.若(u,v)为一条轻边,$ size(v)<size(u)/2$

    2.从根节点到任意节点的路径 经过的轻边数量 小于 logn,经过的重边数量 也小于 logn

    可以得出,树链剖分的时间复杂度为(O(nlog^2n)) ,是一种优秀的算法。

    求出重儿子,深度,子树大小

    void dfs_son(int x,int f){
    	siz[x]=1;fa[x]=f;dep[x]=dep[f]+1;
    	for(int i=hd[x];i;i=nxt[i]){
    		int y=to[i];
    		if(y==f)continue;
    		dfs_son(y,x);
    		siz[x]+=siz[y];
    		if(siz[y]>siz[son[x]])son[x]=y;
    	}
    }
    

    接下来把轻重儿子连成链,所以我们就一定要让链上的点连续

    我们从根开始一遍DFS,如果有重儿子就先走重儿子(将一条重链放到一个区间内),搜到叶子节点后回溯回去再去搜轻儿子(轻链)

    板子

    要处理的问题:

    • 1将树从x到y结点最短路径上所有节点的值都加上z
    • 2求树从x到y结点最短路径上所有节点的值之和
    • 3将以x为根节点的子树内所有节点值都加上z
    • 4求以x为根节点的子树内所有节点值之和

    由于dfs序中一颗子树是连续的一段,3,4就比较好处理了

    对于树上任意两点的路径,设所在链顶端的深度更深的那个点为x点

    • ans加上x点到x所在链顶端 这一段区间的点权和
    • 把x跳到x所在链顶端的那个点的 fa

    不停执行这两个步骤,直到两个点处于一条链上,这时再加上此时两个点的区间和即可

    (O(log^2n))查询

    #include <cstdio>
    #include <iostream>
    #include <vector>
    using namespace std;
    #define ls (p<<1)
    #define rs (p<<1|1)
    const int N=5e5;
    typedef long long LL;
    inline int read(){
        int x=0;char ch=getchar();
        while(!isdigit(ch)) ch=getchar();
        while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
        return x;
    }
    int n,m,root,mod,val[N];
    int to[N],nxt[N],hd[N],tot;
    inline void add(int x,int y){
    	to[++tot]=y;nxt[tot]=hd[x];hd[x]=tot;
    }
    
    int siz[N],dep[N],fa[N],son[N];
    void dfs_son(int x,int f){	
        siz[x]=1;fa[x]=f;dep[x]=dep[f]+1;
        for(int i=hd[x];i;i=nxt[i]){
            int y=to[i];
            if(y==f) continue;
            dfs_son(y,x);
            siz[x]+=siz[y];
            if(siz[y]>siz[son[x]]) son[x]=y;
        }
    }
    int dfn[N],rev[N],top[N],dfn_cnt;
    void dfs_chain(int x,int tp){
        dfn[x]=++dfn_cnt;rev[dfn_cnt]=x;top[x]=tp;
        if(son[x]) dfs_chain(son[x],tp);
        for(int i=hd[x];i;i=nxt[i]){
            int y=to[i];
            if(dfn[y]) continue;
            dfs_chain(y,y);
        }
    }
    
    struct tree{
        int l,r;
        LL tag,sum;
    }t[N];
    inline void push_up(int p){
        t[p].sum=(t[ls].sum+t[rs].sum)%mod;
    }
    void build(int l,int r,int p){
        t[p].l=l;t[p].r=r;
        if(l==r){ t[p].sum=val[rev[l]];return; }
        int mid=(l+r)>>1;
        build(l,mid,ls);
        build(mid+1,r,rs);
        push_up(p);
    }
    void push_down(int p){
        if(!t[p].tag) return;
        (t[ls].tag+=t[p].tag)%=mod;
        (t[rs].tag+=t[p].tag)%=mod;
        (t[ls].sum+=(t[ls].r-t[ls].l+1)*t[p].tag)%=mod;
        (t[rs].sum+=(t[rs].r-t[rs].l+1)*t[p].tag)%=mod;
        t[p].tag=0;
    }
    void modify(int L,int R,LL v,int p){
        if(L<=t[p].l&&t[p].r<=R){
            (t[p].tag+=v)%=mod;
            (t[p].sum+=(t[p].r-t[p].l+1)*v)%=mod;
            return;
        }
        push_down(p);
        int mid=(t[p].l+t[p].r)>>1;
        if(L<=mid) modify(L,R,v,ls);
        if(R>mid) modify(L,R,v,rs);
        push_up(p);
    }
    LL query(int L,int R,int p){
        if(L<=t[p].l&&t[p].r<=R) return t[p].sum;
        
        push_down(p);
        int mid=(t[p].l+t[p].r)>>1;
        LL res=0;
        if(L<=mid) (res+=query(L,R,ls))%=mod;
        if(R>mid) (res+=query(L,R,rs))%=mod;
        return res;
    }
    void update(int x,int y,LL v){
        while(top[x]!=top[y]){
            if(dep[top[x]]<dep[top[y]]) swap(x,y);
            modify(dfn[top[x]],dfn[x],v,1);
            x=fa[top[x]];
        }
        if(dfn[x]>dfn[y]) swap(x,y);
        modify(dfn[x],dfn[y],v,1);
    }
    LL sum(int x,int y){
        LL res=0;
        while(top[x]!=top[y]){
            if(dep[top[x]]<dep[top[y]]) swap(x,y);
            (res+=query(dfn[top[x]],dfn[x],1))%=mod;
            x=fa[top[x]];
        }
        if(dfn[x]>dfn[y]) swap(x,y);
        (res+=query(dfn[x],dfn[y],1))%=mod;   
        return res;
    }
    int main(){
        n=read();m=read();root=read();mod=read();
        for(int i=1;i<=n;i++) val[i]=read();
        for(int i=1,x,y;i<n;i++){
            x=read();y=read();
            add(x,y);add(y,x);
        }
        dfs_son(root,0);
        dfs_chain(root,root);
        build(1,n,1);
        for(int i=1,x,y,z,op;i<=m;i++){
            op=read();x=read();
            if(op==1){
                y=read();z=read();
                update(x,y,z);
            }
            if(op==2){
                y=read();
                printf("%lld
    ",sum(x,y));
            }
            if(op==3){
                z=read();
                modify(dfn[x],dfn[x]+siz[x]-1,z,1);
            }
            if(op==4){
                printf("%lld
    ",query(dfn[x],dfn[x]+siz[x]-1,1));
            }
        }
        return 0;
    }
    
    

    类板子:

    https://www.luogu.com.cn/problem/P3178

    https://www.luogu.com.cn/problem/P2590

    https://www.luogu.com.cn/problem/P3128

    边权转化:

    Qtree1 具体的把边权赋给深度较深的点(在dfs_son时),但有个问题是,我们查 (x,y) 上的最大值,其lca维护的是 lca-->fa[lca] 的边权,实际是不可查到的,所以我们只需在查询最后一步

    https://www.luogu.com.cn/problem/P303

    类似上面

    软件包管理器

    安装—— 1到x的路径赋值为1

    卸载—— x的子树赋值为0

    ans=操作前的总和和操作后的总和

    #include<bits/stdc++.h>
    using namespace std;
    #define N 100010
    #define ls (p<<1)
    #define rs (p<<1|1)
    inline int read() {
    	int x=0,f=1;char ch=getchar();
    	while(!isdigit(ch)) {if(ch=='-')f=-1;ch=getchar();}
    	while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
    	return f*x;
    }
    int n,q;
    char op[10];
    int to[N<<1],nxt[N<<1],hd[N],tot;
    inline void add(int x,int y) {
    	to[++tot]=y;nxt[tot]=hd[x];hd[x]=tot;
    }
    int siz[N],fa[N],son[N],dep[N];
    void dfs_son(int x,int f) {
    	siz[x]=1;fa[x]=f;dep[x]=dep[f]+1;
    	for(int i=hd[x];i;i=nxt[i]) {
    		int y=to[i];
    		if(y==f)continue;
    		dfs_son(y,x);
    		siz[x]+=siz[y];
    		if(siz[y]>siz[son[x]])son[x]=y;
    	}
    }
    int dfn[N],top[N],dfn_cnt;
    void dfs_chain(int x,int tp) {
    	top[x]=tp;
    	dfn[x]=++dfn_cnt;
    	if(son[x])dfs_chain(son[x],tp);
    	for(int i=hd[x];i;i=nxt[i]) {
    		int y=to[i];
    		if(dfn[y])continue;
    		dfs_chain(y,y);
    	}
    }
    struct TREE{
    	int l,r,sum,tag;
    }t[N<<2];
    
    void pushdown(int p) {
    	if(t[p].tag==-1)return;
    	t[ls].tag=t[p].tag;
    	t[rs].tag=t[p].tag;
    	t[ls].sum=t[p].tag*(t[ls].r-t[ls].l+1);
    	t[rs].sum=t[p].tag*(t[rs].r-t[rs].l+1);
    	t[p].tag=-1;
    }
    void build(int L,int R,int p) {
    	t[p].l=L;t[p].r=R;t[p].tag=-1;
    	if(L==R) return;
    	int mid=(L+R)>>1;
    	build(L,mid,ls);
    	build(mid+1,R,rs);
    	t[p].sum=t[ls].sum+t[rs].sum;
    }
    void modify(int L,int R,int add,int p) {
    	if(L<=t[p].l&&t[p].r<=R) {
    		t[p].sum=add*(t[p].r-t[p].l+1);
    		t[p].tag=add;return;
    	}
    	pushdown(p);
    	int mid=(t[p].l+t[p].r)>>1;
    	if(L<=mid) modify(L,R,add,ls);
    	if(mid<R) modify(L,R,add,rs);
    	t[p].sum=t[ls].sum+t[rs].sum;
    }
    void update(int x,int y,int add) {
    	while(top[x]!=top[y]) {
    		if(dep[top[x]]<dep[top[y]]) swap(x,y);
    		modify(dfn[top[x]],dfn[x],add,1);
    		x=fa[top[x]];
    	}
    	if(dfn[x]>dfn[y]) swap(x,y);
    	modify(dfn[x],dfn[y],add,1);
    }
    int main() {
    	n=read();
    	for(int i=2,x;i<=n;++i) {
    		x=read()+1;
    		add(x,i),add(i,x);
    	}
    	dfs_son(1,0);
    	dfs_chain(1,1);
    	build(1,n,1); 
    
    	q=read();
    	while(q--) {
    		int a,bef;
    		bef=t[1].sum;
    		scanf("%s",op);
    		a=read()+1;
    		if(op[0]=='i') {
    			update(1,a,1);
    			printf("%d
    ",abs(bef-t[1].sum));
    		} else {
    			modify(dfn[a],dfn[a]+siz[a]-1,0,1);
    			printf("%d
    ",abs(bef-t[1].sum));
    		}
    	}
    	return 0;
    	
    }
    

    染色

    好题!!

    细节好多哦

    就是要维护个lcol,rcol

    每次合并(包括询问合并)的时候

    if(t[ls].rc==t[rs].lc) ans--
    
    #include<bits/stdc++.h>
    using namespace std;
    #define N 100010
    #define ls (p<<1)
    #define rs (p<<1|1)
    inline int read() {
    	int x=0,f=1;char ch=getchar();
    	while(!isdigit(ch)) {if(ch=='-')f=-1;ch=getchar();}
    	while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
    	return f*x;
    }
    int n,q,a[N];
    
    int to[N<<1],nxt[N<<1],hd[N],tot;
    inline void add(int x,int y) {
    	to[++tot]=y;nxt[tot]=hd[x];hd[x]=tot;
    }
    int siz[N],fa[N],son[N],dep[N];
    void dfs_son(int x,int f) {
    	siz[x]=1;fa[x]=f;dep[x]=dep[f]+1;
    	for(int i=hd[x];i;i=nxt[i]) {
    		int y=to[i];
    		if(y==f)continue;
    		dfs_son(y,x);
    		siz[x]+=siz[y];
    		if(siz[y]>siz[son[x]])son[x]=y;
    	}
    }
    int dfn[N],rev[N],top[N],dfn_cnt;
    void dfs_chain(int x,int tp) {
    	top[x]=tp;
    	dfn[x]=++dfn_cnt;rev[dfn_cnt]=x;
    	if(son[x])dfs_chain(son[x],tp);
    	for(int i=hd[x];i;i=nxt[i]) {
    		int y=to[i];
    		if(dfn[y])continue;
    		dfs_chain(y,y);
    	}
    }
    struct TREE{
    	int val,lc,rc,l,r,tag;
    }t[N<<2];
    inline void pushup(int p) {
    	t[p].val=t[ls].val+t[rs].val-(t[ls].rc==t[rs].lc);
    	t[p].lc=t[ls].lc;t[p].rc=t[rs].rc;//Q
    }
    void pushdown(int p) {//Q
    	if(t[p].tag==-1)return;
    	t[ls].tag=t[rs].tag=t[p].tag;
    	t[ls].val=t[rs].val=1;
    	t[ls].lc=t[ls].rc=t[p].tag;
    	t[rs].lc=t[rs].rc=t[p].tag;
    	t[p].tag=-1;
    }
    void build(int L,int R,int p) {
    	t[p].l=L;t[p].r=R;t[p].tag=-1;
    	if(L==R) {//Q
    		t[p].val=1;
    		t[p].lc=t[p].rc=a[rev[L]];
    		return;
    	}
    	int mid=(L+R)>>1;
    	build(L,mid,ls);
    	build(mid+1,R,rs);
    	pushup(p);
    }
    void modify(int L,int R,int add,int p) {
    	if(L<=t[p].l&&t[p].r<=R) {//Q
    		t[p].val=1;
    		t[p].lc=t[p].rc=t[p].tag=add;
    		return;
    	}
    	pushdown(p);
    	int mid=(t[p].l+t[p].r)>>1;
    	if(L<=mid) modify(L,R,add,ls);
    	if(mid<R) modify(L,R,add,rs);
    	pushup(p);
    }
    TREE query(int L,int R,int p) {
    	if(L<=t[p].l&&t[p].r<=R) return t[p];
    	pushdown(p);
    	int mid=(t[p].l+t[p].r)>>1;
    	if(R<=mid) return query(L,R,ls);
    	else if(L>mid) return query(L,R,rs);
    	else {//Q
    		TREE s1=query(L,R,ls),s2=query(L,R,rs),s;
    		s.val=s1.val+s2.val-(s1.rc==s2.lc);
    		s.lc=s1.lc,s.rc=s2.rc;
    		return s;
    	}
    }
    void upd(int x,int y,int add) {
    	while(top[x]!=top[y]) {
    		if(dep[top[x]]<dep[top[y]]) swap(x,y);
    		modify(dfn[top[x]],dfn[x],add,1);
    		x=fa[top[x]];
    	}
    	if(dfn[x]>dfn[y]) swap(x,y);
    	modify(dfn[x],dfn[y],add,1);
    }
    
    int get(int x,int y) {
    	int ans=0,lc=0,rc=0;TREE s;
    	while(top[x]!=top[y]) {
    		if(dep[top[x]]<dep[top[y]]) swap(x,y),swap(lc,rc);//Qswap
    		s=query(dfn[top[x]],dfn[x],1);
    		ans+=s.val-(s.rc==lc);//Q
    		lc=s.lc;
    		x=fa[top[x]];
    	}
    	if(dfn[x]>dfn[y]) swap(x,y),swap(lc,rc);//Qswap
    	s=query(dfn[x],dfn[y],1);
    	return ans+s.val-(s.lc==lc)-(s.rc==rc);//Q
    }
    
    int main() {
    	n=read();q=read();
    	for(int i=1;i<=n;i++)
    		a[i]=read();
    	for(int i=2,x,y;i<=n;++i) {
    		x=read();y=read();
    		add(x,y),add(y,x);
    	}
    	dfs_son(1,0);
    	dfs_chain(1,1);
    	build(1,n,1); 
    
    	char op;int a,b,c;
    	while(q--) {
    		cin>>op;a=read();b=read();
    		if(op=='C') {
    			c=read();
    			upd(a,b,c);
    		} else {
    			printf("%d
    ",get(a,b));
    		}
    	}
    	return 0;
    }
    

    LNOI2014LCA

    这题统计 l~r 中所有点与z的lca的深度之和。

    暴力就是把lca都求出来。。。显然这题没有暴力分

    所以正解要么是一次求出多个lca不会,要么就是把这个求多个dep的和转化一下。

    dep[i] 其实就是 i 到根有几个点

    比较暴力的方法:我们不妨把 z 到根的路径上的点全部 +1,对于 l 到 r 之间的点询问他们到根路径上的点权和。上面的暴力具有叠加性,且可逆。也就是说我们可以对于 l 到 r 之间的点 i,将 i 到根的路径上的点全部 +1, 转而询问 z 到根的路径上的点(包括自身)的权值和就是这个询问的答案。

    但是考虑到每次统计时,不能很好的排除 l ~ r 区间之外的点对 z->根 这条路径的贡献,所以我们每次都要清空线段树。

    我们每次清空线段树,然后从 l ~ r 再添加一遍,树剖+线段树的复杂度就是 O(n * logn * logn)的,还要做 q 次,复杂度依然不理想。

    把询问差分下,也就是用 [1, r] − [1, l − 1] 来计算答案,每个拆开的区间之间是有重叠的,是可以转移的,而不用每次都清空。

    所以我们可以将差分后的区间按照端点从小到大排序(左端点都是根),然后按从小到大的顺序添加点,每遇到一个询问就查询一次,从而排除掉区间之外的点的影响,也就优化掉一个 q 的复杂度。

    #include <queue>
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    #define ls (p<<1)
    #define rs (p<<1|1)
    #define mid ((l+r)>>1)
    const int N=100005; 
    inline int read(){
    	int x=0,f=1;char ch=getchar();
    	while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    	while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
    	return f*x;
    }
    
    int n,m;
    int to[N<<1],nxt[N<<1],hd[N],tot;
    inline void add(int x,int y) {
    	to[++tot]=y;nxt[tot]=hd[x];hd[x]=tot;
    }
    int siz[N],fa[N],son[N],dep[N];
    void dfs_son(int x,int f) {
    	siz[x]=1;fa[x]=f;dep[x]=dep[f]+1;
    	for(int i=hd[x];i;i=nxt[i]) {
    		int y=to[i];
    		if(y==f)continue;
    		dfs_son(y,x);
    		siz[x]+=siz[y];
    		if(siz[y]>siz[son[x]])son[x]=y;
    	}
    }
    int dfn[N],rev[N],top[N],dfn_cnt;
    void dfs_chain(int x,int tp) {
    	top[x]=tp;
    	dfn[x]=++dfn_cnt;rev[dfn_cnt]=x;
    	if(son[x])dfs_chain(son[x],tp);
    	for(int i=hd[x];i;i=nxt[i]) {
    		int y=to[i];
    		if(dfn[y])continue;
    		dfs_chain(y,y);
    	}
    }
    
    struct TREE{
        int len,sum,tag;
    }t[N<<2];
    struct node{
        int ans,z;
    }q[N];
    void build(int l,int r,int p) {
        t[p].len=r-l+1;
        if(l==r) return;
        build(l,mid,ls);
        build(mid+1,r,rs);
    }
    void pushdown(int p) {
        if(!t[p].tag) return;
        t[ls].tag+=t[p].tag;
        t[rs].tag+=t[p].tag;
        t[ls].sum+=t[p].tag*t[ls].len;
        t[rs].sum+=t[p].tag*t[rs].len;
        t[p].tag=0;
    }
    void modify(int l,int r,int L,int R,int p) {
        if(L<=l&&r<=R) {
            t[p].tag++;
            t[p].sum+=t[p].len;
            return;
        }
        pushdown(p);
        if(L<=mid) modify(l,mid,L,R,ls);
        if(R>mid) modify(mid+1,r,L,R,rs);
        t[p].sum=t[ls].sum+t[rs].sum;
    }
    void upd(int x,int y) {
        while(top[x]!=top[y]) {
            if(dep[top[x]]<dep[top[y]]) swap(x,y);
            modify(1,n,dfn[top[x]],dfn[x],1);
            x=fa[top[x]];
        }
        if(dfn[x]>dfn[y]) swap(x,y);
        modify(1,n,dfn[x],dfn[y],1);
    }
    int query(int l,int r,int L,int R,int p) {
        if(L<=l&&r<=R) return t[p].sum;
        pushdown(p);
        int ans=0;
        if(L<=mid) ans+=query(l,mid,L,R,ls);
        if(R>mid) ans+=query(mid+1,r,L,R,rs);
        return ans;
    }
    int getsum(int x,int y) {
        int ans=0;
        while(top[x]!=top[y]) {
            if(dep[top[x]]<dep[top[y]]) swap(x,y);
            ans+=query(1,n,dfn[top[x]],dfn[x],1);
            x=fa[top[x]];
        }
        if(dfn[x]>dfn[y]) swap(x,y);
        return ans+query(1,n,dfn[x],dfn[y],1);
    }
    struct QUES{
        int p,id;bool flag;
        QUES() {}
        QUES(int p_,int id_,bool flag_):p(p_),id(id_),flag(flag_){}
        bool operator < (const QUES &x) const {
            return p<x.p;
        }
    }a[N];
    int main(){
    	n=read();m=read();
        for(int i=2,x;i<=n;i++) {
            x=read()+1;
            add(i,x);add(x,i);
        }
        dfs_son(1,0);
        dfs_chain(1,1);
        build(1,n,1);
        for(int i=1;i<=m;i++) {
            a[i*2-1]=QUES(read(),i,0);
            a[i*2]=QUES(read()+1,i,1);
            q[i].z=read()+1;
        }
        sort(a+1,a+1+2*m);
        int now=0;
        for(int i=1;i<=2*m;i++) {
            while(now<a[i].p) {
                now++;
                upd(1,now);
            }
            int r=getsum(1,q[a[i].id].z);
            q[a[i].id].ans+=a[i].flag?r:(-r);
        }
        for(int i=1;i<=m;i++)
            printf("%d
    ",q[i].ans%201314);
    	return 0;
    }
    
    

    松鼠的新家

    树剖写法(差分更简单)

    #include <cstdio>
    #include <iostream>
    #include <vector>
    using namespace std;
    #define ls (p<<1)
    #define rs (p<<1|1)
    const int N=5e6;
    inline int read(){
        int x=0;char ch=getchar();
        while(!isdigit(ch)) ch=getchar();
        while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
        return x;
    }
    int n,val[N],ans;
    int to[N],nxt[N],hd[N],tot;
    inline void add(int x,int y){
    	to[++tot]=y;nxt[tot]=hd[x];hd[x]=tot;
    }
    
    int siz[N],dep[N],fa[N],son[N];
    void dfs_son(int x,int f){
        siz[x]=1;fa[x]=f;dep[x]=dep[f]+1;
        for(int i=hd[x];i;i=nxt[i]){
            int y=to[i];
            if(y==f) continue;
            dfs_son(y,x);
            siz[x]+=siz[y];
            if(siz[y]>siz[son[x]]) son[x]=y;
        }
    }
    int dfn[N],rev[N],top[N],dfn_cnt;
    void dfs_chain(int x,int tp){
        dfn[x]=++dfn_cnt;rev[dfn_cnt]=x;top[x]=tp;
        if(son[x]) dfs_chain(son[x],tp);
        for(int i=hd[x];i;i=nxt[i]){
            int y=to[i];
            if(dfn[y]) continue;
            dfs_chain(y,y);
        }
    }
    
    struct tree{
        int l,r;
        int tag,sum;
    }t[N];
    inline void push_up(int p){
        t[p].sum=(t[ls].sum+t[rs].sum);
    }
    void build(int l,int r,int p){
        t[p].l=l;t[p].r=r;
        if(l==r) return; 
        int mid=(l+r)>>1;
        build(l,mid,ls);
        build(mid+1,r,rs);
        push_up(p);
    }
    void push_down(int p){
        if(!t[p].tag) return;
        t[ls].tag+=t[p].tag;
        t[rs].tag+=t[p].tag;
        t[ls].sum+=(t[ls].r-t[ls].l+1)*t[p].tag;
        t[rs].sum+=(t[rs].r-t[rs].l+1)*t[p].tag;
        t[p].tag=0;
    }
    void modify(int L,int R,int v,int p){
        if(L<=t[p].l&&t[p].r<=R){
            t[p].tag+=v;
            t[p].sum+=(t[p].r-t[p].l+1)*v;
            return;
        }
        push_down(p);
        int mid=(t[p].l+t[p].r)>>1;
        if(L<=mid) modify(L,R,v,ls);
        if(R>mid) modify(L,R,v,rs);
        push_up(p);
    }
    int query(int L,int R,int p){
        if(L<=t[p].l&&t[p].r<=R) return t[p].sum;
        push_down(p);
        int mid=(t[p].l+t[p].r)>>1;
        int res=0;
        if(L<=mid) res+=query(L,R,ls);
        if(R>mid) res+=query(L,R,rs);
        return res;
    }
    void update(int x,int y,int v){
        while(top[x]!=top[y]){
            if(dep[top[x]]<dep[top[y]]) swap(x,y);
            modify(dfn[top[x]],dfn[x],v,1);
            x=fa[top[x]];
        }
        if(dfn[x]>dfn[y]) swap(x,y);
        modify(dfn[x],dfn[y],v,1);
    }
    int main(){
        n=read();
        for(int i=1;i<=n;i++) val[i]=read();
        for(int i=1,x,y;i<n;i++){
            x=read();y=read();
            add(x,y);add(y,x);
        }
        dfs_son(1,0);
        dfs_chain(1,1);
        build(1,n,1);
        for(int i=1;i<n;i++){
            int x=val[i],y=val[i+1];
            update(x,y,1);
            update(y,y,-1);
        }
        for(int i=1;i<=n;i++){
            ans=query(dfn[i],dfn[i],1);
            printf("%d
    ",ans);
        }
        return 0;
    }
    
  • 相关阅读:
    高斯函数 and 对数高斯函数 拟合曲线
    Python3.6、3.7、3.8新特性
    常用限流策略——漏桶与令牌桶介绍
    常用的HTTP服务压测工具介绍
    使用swagger生成接口文档
    validator库参数校验若干实用技巧
    树形结构数据处理
    element-ui 抽屉组件(el-drawer ) 二次封装 增加resize拖曳改变宽度大小
    pm2常用命令
    vue3-- setup中获取数组dom
  • 原文地址:https://www.cnblogs.com/ke-xin/p/13568212.html
Copyright © 2011-2022 走看看