ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

20220713树剖

2022-07-13 09:36:21  阅读:143  来源: 互联网

标签:20220713 return 树剖 int siz dep ans cu


A

树剖求lca
板子

C

一道树剖板子题

D

树剖题单里混进了一个奇怪的东西
根号分治
对于跳的步长大于sqrt(n),我们直接暴力跳就行了
而步长小于时维护从某点一直以某一步长跳到根的和,然后使用差分求得答案。

点击查看代码
#include<bits/stdc++.h>
#define M 50005
#define N 250
using namespace std;
int n,dep[M],f[M][20],g[M][N],len,a[M],hd[M],cnt,val[M][N],b[M],c[M];
struct node{int nxt,to;}e[M<<1];
void add(int u,int v){e[++cnt].nxt=hd[u];e[cnt].to=v;hd[u]=cnt;}
void dfs(int u,int fa){
	g[u][1]=f[u][0]=fa;dep[u]=dep[fa]+1;
	for(int i=hd[u];i;i=e[i].nxt){
		int v=e[i].to;
		if(v==fa) continue;
		dfs(v,u);
	}
}
void dfss(int u){
	for(int i=1;i<=len;++i){ val[u][i]=val[g[u][i]][i]+a[u];}
	for(int i=hd[u];i;i=e[i].nxt){
		int v=e[i].to;
		if(v==f[u][0]) continue;
		dfss(v);
	}
}
int lca(int a,int b){
	if(dep[a]<dep[b]) swap(a,b);
	int k=dep[a]-dep[b];
	for(;k;k-=(k&(-k))) a=f[a][__builtin_ctz(k)];
	if(a==b) return a;
	for(int j=18;~j;--j){
		if(f[a][j]!=f[b][j]) a=f[a][j],b=f[b][j];
	}	
	return f[a][0];
}
int find(int x,int k){
	for(;k;k-=(k&(-k))) x=f[x][__builtin_ctz(k)];
	return x;
}
int up(int x,int y,int k){
	if(dep[x]<dep[y]) return 0;
	int ans=0,gu;
	if(k<len) ans+=val[x][k],gu=k-(dep[x]-dep[y])%k,ans-=val[find(y,gu%k)][k];
	else while(dep[x]>dep[y]) ans+=a[x],x=find(x,k);
	return ans;
}
int main(){
	scanf("%d",&n);len=sqrt(n);
	for(int i=1;i<=n;++i) scanf("%d",&a[i]);
	int u,v;
	for(int i=1;i<n;++i){
		scanf("%d%d",&u,&v);
		add(u,v);add(v,u);
	}
	dfs(1,0);
	for(int j=1;(1<<j)<=n;++j)
		for(int i=1;i<=n;++i)
			f[i][j]=f[f[i][j-1]][j-1];
	for(int j=2;j<=len;++j)
		for(int i=1;i<=n;++i)
			g[i][j]=g[g[i][1]][j-1];
	dfss(1);
	for(int i=1;i<=n;++i) scanf("%d",&b[i]);
	for(int i=2;i<=n;++i) scanf("%d",&c[i]);
	int ans;
	for(int i=2;i<=n;++i){
		int l=b[i-1],r=b[i],k=c[i];
		int L=lca(l,r);
		ans=up(l,L,k);
		if((dep[l]+dep[r]-dep[L]-dep[L])%k) ans+=a[r],r=find(r,(dep[l]+dep[r]-dep[L]-dep[L])%k);
		ans+=up(r,f[L][0],k);
		printf("%d\n",ans);
	}
	return 0;
}

E

标准的树剖题,线段树维护时注意需要的标记(区间答案,左右颜色)

F

首先先树剖,子树修改的时候只需要区间修改就行了,
而多个链的查询呢?
我们发现k<=5,所以可以使用容斥,其中多个链的交集显然为下端点的lca与最深的上端点之间的距离(而几个上端点并非是祖先后代关系的话,那显然没有交集)

ui solve(int qwe){
    int L=0,R=0;
    ui ans=0;
    for(int i=1;i<=5;++i)
        if(qwe&(1<<(i-1))){
            if(!L) L=_l[i];
            else L=lca(L,_l[i]);
            if(dep[R]<dep[_r[i]]) R=_r[i];
        }
    // printf("%d %d\n",L,R);
    if(dep[L]<dep[R]) return 0;
    // printf("qwe");
    while(tp[L]!=tp[R]){
        if(dep[tp[L]]<dep[tp[R]]) swap(L,R);
        ans+=tr.ck(1,1,n,cu[tp[L]],cu[L]);
        L=f[tp[L]];
    }   
    if(dep[L]>dep[R]) swap(L,R);
    ans+=tr.ck(1,1,n,cu[L],cu[R]);
    // printf("%u\n",ans);
    return ans;
}

其他部分就是正常的树剖了

点击查看代码
#include<bits/stdc++.h>
#define ui unsigned
#define M 200005
using namespace std;
int n,f[M],dep[M],siz[M],sn[M],tp[M],cu[M],tot,_l[10],_r[10],rong_chi[105];
vector<int> e[M];
void dfs1(int u,int fa){
    f[u]=fa;dep[u]=dep[fa]+1;siz[u]=1;
    for(int v:e[u]){
        if(v==f[u]) continue;
        dfs1(v,u);
        siz[u]+=siz[v];
        if(siz[sn[u]]<siz[v]) sn[u]=v; 
    }
}
void dfs2(int u,int t){
    tp[u]=t;cu[u]=++tot;
    if(sn[u]) dfs2(sn[u],t);
    for(int v:e[u]){
        if(v==f[u]||v==sn[u]) continue;
        dfs2(v,v);
    }
}
int lca(int l,int r){
    while(tp[l]!=tp[r]){
        if(dep[tp[l]]<dep[tp[r]]) swap(l,r);
        l=f[tp[l]];
    }
    if(dep[l]>dep[r]) swap(l,r);
    return l;
}
struct Seg_tree{
    ui sm[M<<2],lzy[M<<2];
    void pushup(int p){
        sm[p]=sm[p<<1]+sm[p<<1|1];
    }
    void pushdown(int p,int l,int r){
        int mid=(l+r)>>1;
        sm[p<<1]+=lzy[p]*(mid-l+1);
        sm[p<<1|1]+=lzy[p]*(r-mid);
        lzy[p<<1]+=lzy[p];
        lzy[p<<1|1]+=lzy[p];
        lzy[p]=0;
    }
    void add(int p,int l,int r,int L,int R,ui qwe){
        if(L<=l&&r<=R){
            sm[p]+=qwe*(r-l+1);lzy[p]+=qwe;
            return ;
        }
        pushdown(p,l,r);
        int mid=(l+r)>>1;
        if(L<=mid) add(p<<1,l,mid,L,R,qwe);
        if(R>mid) add(p<<1|1,mid+1,r,L,R,qwe);
        pushup(p);
    }
    ui ck(int p,int l,int r,int L,int R){
        if(L<=l&&r<=R) return sm[p];
        pushdown(p,l,r);
        ui ans=0;
        int mid=(l+r)>>1;
        if(L<=mid) ans+=ck(p<<1,l,mid,L,R);
        if(R>mid) ans+=ck(p<<1|1,mid+1,r,L,R);
        return ans;
    }
}tr;
ui solve(int qwe){
    int L=0,R=0;
    ui ans=0;
    for(int i=1;i<=5;++i)
        if(qwe&(1<<(i-1))){
            if(!L) L=_l[i];
            else L=lca(L,_l[i]);
            if(dep[R]<dep[_r[i]]) R=_r[i];
        }
    // printf("%d %d\n",L,R);
    if(dep[L]<dep[R]) return 0;
    // printf("qwe");
    while(tp[L]!=tp[R]){
        if(dep[tp[L]]<dep[tp[R]]) swap(L,R);
        ans+=tr.ck(1,1,n,cu[tp[L]],cu[L]);
        L=f[tp[L]];
    }   
    if(dep[L]>dep[R]) swap(L,R);
    ans+=tr.ck(1,1,n,cu[L],cu[R]);
    // printf("%u\n",ans);
    return ans;
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=31;++i){
        rong_chi[i]=-1;
        for(int j=i;j;j-=(j&(-j))) rong_chi[i]*=-1;     
    }
    // for(int i=1;i<=31;++i) printf("%d ",rong_chi[i]);
    int u,v;
    for(int i=1;i<n;++i){
        scanf("%d%d",&u,&v);
        e[u].push_back(v);e[v].push_back(u);
    }
    dfs1(1,0);dfs2(1,1);
    int q,op,k;
    ui sm;
    scanf("%d",&q);
    while(q--){
        scanf("%d",&op);
        if(op==0){
            scanf("%d%u",&u,&sm);
            tr.add(1,1,n,cu[u],cu[u]+siz[u]-1,sm);
        }
        else{
            ui ans=0;
            scanf("%d",&k);
            for(int i=1;i<=k;++i){scanf("%d%d",&_l[i],&_r[i]);if(dep[_l[i]]<dep[_r[i]]) swap(_l[i],_r[i]);}
            for(int i=1;i<(1<<k);++i) if(rong_chi[i]==1) ans+=solve(i); else ans-=solve(i);
            printf("%u\n",ans%(1ll<<31));
        }
    }
    return 0;
}

标签:20220713,return,树剖,int,siz,dep,ans,cu
来源: https://www.cnblogs.com/goldenwalnut/p/16472615.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有