树剖的魅力

版权声明: https://blog.csdn.net/qq_40828060/article/details/83028157


当然是TLE _题记


P3384 树剖模板

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
typedef unsigned long long ull;
int const maxn=100110,maxm=100110;
int n,q,p,root;
//*******以下为存图部分********
struct E
{
    int to,next;
    E(int to=0,int next=0):
        to(to),next(next){}
}e[maxn<<1];
int head[maxn],cnt2;
void rem()
{
    memset(head,-1,sizeof(head));
}
void add(int u,int v)
{
    e[++cnt2]=(E){v,head[u]};
    head[u]=cnt2;
}
//*********以下为剖树部分**********
int dep[maxn],fa[maxn],size[maxn],hson[maxn];
int id[maxn],top[maxn],w[maxn],val[maxn],tot;
int pre_dfs(int u,int f)
{
    dep[u]=dep[f]+1;
    fa[u]=f;
    size[u]=1;
    int maxson=-1;
    for(int i=head[u];i!=-1;i=e[i].next)
    {
        int v=e[i].to;
        if(v==f)
            continue;
        size[u]+=pre_dfs(v,u);
        if(maxson<size[v])
        {
            hson[u]=v;
            maxson=size[v];
        }
    }
    return size[u];
}
void mark_dfs(int u,int topf)
{
    id[u]=++tot;
    top[u]=topf;
    w[tot]=val[u];
    // if(!hson[u])
    if(size[u]==1)
        return;
    mark_dfs(hson[u],topf);
    for(int i=head[u];i!=-1;i=e[i].next)
    {
        int v=e[i].to;
        if(!id[v])
            mark_dfs(v,v);
            //轻边的链顶自然是轻儿子
    }
}
//********以下为线段树部分********
int cnt=1;
//根节点
struct Tree
{
    int lc,rc,sum,tag;
}a[maxn<<1];
void pushup(int u)
{
    a[u].sum=a[a[u].lc].sum+a[a[u].rc].sum;
}
void build(int u,int l,int r)
{
    if(l==r)
    {
        a[u].sum=w[l];
        //l为序列的点
        return;
    }
    int mid=(l+r)/2;
    a[u].lc=++cnt;
    build(a[u].lc,l,mid);
    a[u].rc=++cnt;
    build(a[u].rc,mid+1,r);
    pushup(u);
}
void pushdown(int u,int l,int r)
{
    int mid=(l+r)/2;
    int tag=a[u].tag,lc=a[u].lc,rc=a[u].rc;
    a[lc].sum=(a[lc].sum%p+((mid-l+1)%p*tag%p)%p)%p;
    a[lc].tag=(a[lc].tag%p+tag%p)%p;
    a[rc].sum=(a[rc].sum%p+((r-mid)%p*tag%p)%p)%p;
    a[rc].tag=(a[rc].tag%p+tag%p)%p;
    a[u].tag=0;
}
void update(int u,int l,int r,int ll,int rr,int dlt)
{
    if(l==ll&&r==rr)
    {
        a[u].sum=(a[u].sum%p+(dlt%p*(r-l+1)%p)%p)%p;
        //Navie
        a[u].tag=(a[u].tag%p+dlt%p)%p;
        return;
    }
    pushdown(u,l,r);
    int mid=(l+r)/2;
    if(mid>=rr)
        //喜闻乐见的错误
        update(a[u].lc,l,mid,ll,rr,dlt);
    else if(mid<ll)
        update(a[u].rc,mid+1,r,ll,rr,dlt);
    else
    {
        update(a[u].lc,l,mid,ll,mid,dlt);	
        update(a[u].rc,mid+1,r,mid+1,rr,dlt);
    }
    pushup(u);
}
int query(int u,int l,int r,int ll,int rr)
{
    if(l==ll&&r==rr)
        return a[u].sum;
    pushdown(u,l,r);
    int mid=(l+r)/2;
    return mid>=ll&&mid<rr?(query(a[u].lc,l,mid,ll,mid)%p+query(a[u].rc,mid+1,r,mid+1,rr)%p)%p:(mid<ll?query(a[u].rc,mid+1,r,ll,rr)%p:query(a[u].lc,l,mid,ll,rr)%p);
}
/*
int query(int u,int l,int r,int ll,int rr)
{
    if(l==ll&&r==rr)
        return a[u].sum;
    pushdown(u,l,r);
    int mid=(l+r)/2;
    if(mid>=ll&&mid<rr)
        return (query(a[u].lc,l,mid,ll,mid)%p+query(a[u].rc,mid+1,r,mid+1,rr)%p)%p;
    return mid<ll?query(a[u].rc,mid+1,r,ll,rr)%p:query(a[u].lc,l,mid,ll,rr)%p;
}
*/
//********以下为线段树维护树链信息*********
void TL_update(int x,int y,int dlt)
{
    while(top[x]!=top[y])
    {
        if(dep[top[x]]<dep[top[y]])
            std::swap(x,y);
        update(1,1,n,id[top[x]],id[x],dlt);
        x=fa[top[x]];
    }
    if(dep[x]>dep[y])
        std::swap(x,y);
    update(1,1,n,id[x],id[y],dlt);
}
int TL_query(int x,int y)
{
    int ans=0;
    while(top[x]!=top[y])
    {
        if(dep[top[x]]<dep[top[y]])
            std::swap(x,y);
        ans=(ans%p+query(1,1,n,id[top[x]],id[x]))%p;
        //dep比较小的为左区间
        x=fa[top[x]];
    }
    if(dep[x]>dep[y])
        std::swap(x,y);
    ans=(ans%p+query(1,1,n,id[x],id[y]))%p;
    return ans;
}
//********以下为线段树维护子树信息********
void Tr_update(int x,int dlt)
{
    update(1,1,n,id[x],id[x]+size[x]-1,dlt);
    //一直不懂
}
int Tr_query(int x)
{
    return query(1,1,n,id[x],id[x]+size[x]-1);
}
//**********以下为读入部分***********
void read()
{
    scanf("%d%d%d%d",&n,&q,&root,&p);
    for(int i=1;i<=n;i++)
        scanf("%d",&val[i]),val[i]%=p;
    for(int x,y,i=1;i<n;i++)
        scanf("%d%d",&x,&y),add(x,y),add(y,x);
}
int main()
{
    memset(head,-1,sizeof(head));
    read();
    dep[root]=-1,
    pre_dfs(root,0);
    mark_dfs(root,root);
    build(1,1,n);
    for(int op,x,y,i=1;i<=q;i++)
    {
        scanf("%d%d",&op,&x);
        if(op==4)
        {
            printf("%d\n",Tr_query(x));
            continue;
        }
        scanf("%d",&y);
        if(op==1)
        {
            int z;scanf("%d",&z);
            TL_update(x,y,z);
        }
        else if(op==2)
            printf("%d\n",TL_query(x,y));
        else
            Tr_update(x,y);
    }
    return 0;
}

P3376 树剖求LCA

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
typedef unsigned long long ull;
int const maxn=500100,maxm=500100;
int n,q,root;
//******************************************
struct E
{
	int to,next;
	E(int to=0,int next=0):
		to(to),next(next){}
}e[maxm<<1];
int head[maxn],cnt;
void add(int u,int v)
{
	e[++cnt]=(E){v,head[u]};
	head[u]=cnt;
}
//******************************************
int dep[maxn],size[maxn],hson[maxn],fa[maxn];
int top[maxn],tot;
int pre_dfs(int u,int f)
{
	dep[u]=dep[f]+1;
	fa[u]=f;
	size[u]=1;
	int maxson=-1;
	for(int i=head[u];i;i=e[i].next)
	{
		int v=e[i].to;
		if(v==f)
			continue;
		size[u]+=pre_dfs(v,u);
		if(maxson<size[v])
		{
			maxson=size[v];
			hson[u]=v;
		}
	}
	return size[u];
}
void mark_dfs(int u,int topf)
{
	top[u]=topf;
	if(size[u]==1)
		return;
	mark_dfs(hson[u],topf);
	for(int i=head[u];i;i=e[i].next)
	{
		int v=e[i].to;
		if(v==fa[u])
			continue;
		if(v!=hson[u])
			mark_dfs(v,v);
	}
}
//*****************************************
int	LCA(int x,int y)
{
	while(top[x]!=top[y])
	{
		if(dep[top[x]]<dep[top[y]])
			std::swap(x,y);
		x=fa[top[x]];
	}
	if(dep[x]>dep[y])
		std::swap(x,y);
	return x;
}
int main()
{
	scanf("%d%d%d",&n,&q,&root);
	for(int x,y,i=1;i<n;i++)
		scanf("%d%d",&x,&y),add(x,y),add(y,x);
	dep[root]=-1;
	pre_dfs(root,0);
	mark_dfs(root,root);
	for(int x,y,i=1;i<=q;i++)
	{
		scanf("%d%d",&x,&y);
		printf("%d\n",LCA(x,y));
	}
	return 0;
}

P1967 货车运输

!这道题要好好说说了,喵的坑了我一上午
虽说一看就是道最大生成树+树剖维护链上最小值的水题,但介于这是我打的第一道树剖题,还是出了不少岔子

注意事项
1、这题需要化边权为点权,显然是要将边权下放到儿子上,因为对于一个点来说父亲只有一个,儿子可能有多个
2、根节点要特殊处理!,因为没有深度比根更小的点,所以根不会也不能对答案产生影响,对于这道题来说,需要赋一个极大值
3、该图不保证联通,所以要建最大生成森林,而且要以多个点为根节点跑dfs
4、不要把并查集的fa1[]和维护树点父亲的fa2[]搞混!!!
5、最大的坑点!当我以为可以线段树暴力查询的时候,我惊奇的发现待查询的两个点的LCA会对结果产生影响,这是因为每个点的点权实际上存的是连向父亲边的权,因此我们需要把LCA的点权给干掉,因为压根就不会经过那条边,具体操作为把LCA的id+1,因为LCA的深度小,作为查询的左区间
6、哈哈哈哈哈哈你以为这样就结束了?LCA的深度一定小么?当两条轻链都向上跳的时候有可能会跳到同一个点,需要特判

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
typedef unsigned long long ull;
int const maxn=500100,maxm=500100,inf=0x1f1f1f1f;
int n,m,q,num,root[maxn],cur;
//*******************************************
struct E
{
	int to,next,w;
	E(int to=0,int next=0,int w=0):
		to(to),next(next),w(w){}
}e[maxn<<1];
int head[maxn],cnt;
void add(int u,int v,int w)
{
	e[++cnt]=(E){v,head[u],w};
	head[u]=cnt;
//	printf("%d%d,",v,u);
}
//*******************************************
int dep[maxn],size[maxn],fa[maxn],hson[maxn];
int top[maxn],id[maxn],w[maxn],val[maxn],tot;
int pre_dfs(int u,int ff)
{
	dep[u]=dep[ff]+1;
	fa[u]=ff;
	size[u]=1;
	int maxson=-1;
	for(int i=head[u];i!=-1;i=e[i].next)
	{
		int v=e[i].to,w=e[i].w;
		if(v==ff)
			continue;
		val[v]=w;
		size[u]+=pre_dfs(v,u);
		if(maxson<size[v])
		{
			maxson=size[v];
			hson[u]=v;
		}
	}
	return size[u];
}
void mark_dfs(int u,int topf)
{
	id[u]=++tot;
	top[u]=topf;
	w[tot]=val[u];
	if(size[u]==1)
		return;
	mark_dfs(hson[u],topf);
	for(int i=head[u];i!=-1;i=e[i].next)
	{
		int v=e[i].to;
		if(!id[v])
			mark_dfs(v,v);
	}
}
//*******************************************
struct Tree
{
	int lc,rc,min;
}a[maxn];
int t=1;
void build(int u,int l,int r)
{
	if(l==r)
	{
		a[u].min=w[l];
		return;
	}
	int mid=(l+r)/2;
	a[u].lc=++t;build(a[u].lc,l,mid);
	a[u].rc=++t;build(a[u].rc,mid+1,r);
	a[u].min=std::min(a[a[u].lc].min,a[a[u].rc].min);
}
int query(int u,int l,int r,int ll,int rr)
{
	if(l==ll&&r==rr)
		return a[u].min;
	int mid=(l+r)/2;
	return mid>=ll&&mid<rr?std::min(query(a[u].lc,l,mid,ll,mid),query(a[u].rc,mid+1,r,mid+1,rr)):(mid>=rr?query(a[u].lc,l,mid,ll,rr):query(a[u].rc,mid+1,r,ll,rr));
	//ll是待修改区间,l是当前处理到的区间,不要混淆! 
}
//*******************************************
int TL_query(int x,int y)
{
	int ans=inf;
	while(top[x]!=top[y])
	{
		if(dep[top[x]]<dep[top[y]])
			std::swap(x,y);
		ans=std::min(ans,query(1,1,n,id[top[x]],id[x]));
		x=fa[top[x]];
	}
	if(dep[x]>dep[y])
		std::swap(x,y);
	if(x!=y)
	//深坑!
		ans=std::min(ans,query(1,1,n,id[x]+1,id[y]));
	return ans;
}
//*******************************************
struct RE
{
	int u,v,w;
	int operator <(const RE &b)const
	{
		return w>b.w;
	}
}ee[maxm];
int f[maxn];
int find(int x)
{
	return x==f[x]?x:f[x]=find(f[x]);
}
void kruskal()
{
	for(int i=1;i<=n;i++)
		f[i]=i;
	std::sort(ee+1,ee+1+m);
	for(int i=1;i<=m;i++)
	{
		int w=ee[i].w,u=ee[i].u,v=ee[i].v,
		fu=find(u),
		fv=find(v);
//		printf("%d %d,,,\n",fu,fv);
		if(fu==fv)
			continue;
		f[fu]=fv;
//		printf("!%d %d:%d\n",u,v,w);
		add(u,v,w),add(v,u,w);
	}
}
//*******************************************
int main()
{
	memset(head,-1,sizeof(head));
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++)
		scanf("%d%d%d",&ee[i].u,&ee[i].v,&ee[i].w);
	kruskal();
//	/*
	for(int i=1;i<=n;i++)
		if(!size[i])
			dep[i]=-1,pre_dfs(i,0),val[i]=inf,root[++cur]=i;
	for(int i=1;i<=cur;i++)
		mark_dfs(root[i],root[i]);
//	for(int i=1;i<=n;i++)
//		printf("!%d %d\n",i,id[i]);
	build(1,1,n);
//	*/
	scanf("%d",&q);
	for(int x,y,i=1;i<=q;i++)
	{
		scanf("%d%d",&x,&y);
		if(find(x)!=find(y))
		{
			printf("-1\n");
			continue;
		}
		printf("%d\n",TL_query(x,y));
	}
	return 0;
}

P3128 Max Flow

感觉我是真的蠢…
明知道是求区间最值和求和完全弄混了…

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
typedef unsigned long long ull;
int const maxn=50100,maxm=50100,inf=0x1f1f1f1f;
int n,q;
// ********************************
struct E
{
    int to,next;
    E(int to=0,int next=0):
        to(to),next(next){}
}e[maxn<<1];
int head[maxn],cnt;
void add(int u,int v)
{
    e[++cnt]=(E){v,head[u]};
    head[u]=cnt;
}
//*********************************
int dep[maxn],size[maxn],fa[maxn],hson[maxn];
int id[maxn],top[maxn],tot;
int pre_dfs(int u,int f)
{
    dep[u]=dep[f]+1;
    fa[u]=f;
    size[u]=1;
    int maxson=-1;
    for(int i=head[u];i;i=e[i].next)
    {
        int v=e[i].to;
        if(v==f)
            continue;
        size[u]+=pre_dfs(v,u);
        if(size[v]>maxson)
        {
            maxson=size[v];
            hson[u]=v;
        }
    }
    return size[u];
}
void mark_dfs(int u,int topf)
{
    id[u]=++tot;
    top[u]=topf;
    if(size[u]==1)
        return;
    mark_dfs(hson[u],topf);
    for(int i=head[u];i;i=e[i].next)
    {
        int v=e[i].to;
        if(!id[v])
            mark_dfs(v,v);
    }
}
//*********************************
struct Tree
{
    int lc,rc,max,tag;
}a[maxn<<1];
int t=1;
void pushup(int u)
{
    a[u].max=std::max(a[a[u].lc].max,a[a[u].rc].max);
}
void pushdown(int u,int l,int r)
{
	int tag=a[u].tag,lc=a[u].lc,rc=a[u].rc;
	a[lc].max+=tag,a[lc].tag+=tag;
	a[rc].max+=tag,a[rc].tag+=tag;
	a[u].tag=0;
}
void build(int u,int l,int r)
{
    if(l==r)
        return;
    int mid=(l+r)/2;
    a[u].lc=++t;build(a[u].lc,l,mid);
    a[u].rc=++t;build(a[u].rc,mid+1,r);
}
void update(int u,int l,int r,int ll,int rr)
{
    if(l==ll&&r==rr)
    {
        a[u].max++;
        a[u].tag++;
//		printf("!!!%d %d %d\n",l,r,a[u].max);
        return;
    }
    pushdown(u,l,r);
    int mid=(l+r)/2;
    if(mid>=rr)
        update(a[u].lc,l,mid,ll,rr);
    else if(mid<ll)
        update(a[u].rc,mid+1,r,ll,rr);
    else
    {
        update(a[u].lc,l,mid,ll,mid);	
        update(a[u].rc,mid+1,r,mid+1,rr);
    }
    pushup(u);
}
//*********************************
void TL_update(int x,int y)
{
    while(top[x]!=top[y])
    {
        if(dep[top[x]]<dep[top[y]])
            std::swap(x,y);
        update(1,1,n,id[top[x]],id[x]);
        x=fa[top[x]];
    }
    if(dep[x]>dep[y])
        std::swap(x,y);
    update(1,1,n,id[x],id[y]);
}
//*********************************
int main()
{
//	freopen("in.in","r",stdin);
    scanf("%d%d",&n,&q);
    for(int x,y,i=1;i<n;i++)
        scanf("%d%d",&x,&y),add(x,y),add(y,x);
    dep[1]=-1,pre_dfs(1,0);
//	puts("shit\n");
    mark_dfs(1,1);
//	for(int i=1;i<=n;i++)
//		printf("!!!%d %d\n",i,id[i]);
    build(1,1,n);
    for(int x,y,i=1;i<=q;i++)
        scanf("%d%d",&x,&y),/*printf("id:%d %d\n",id[x],id[y]),*/TL_update(x,y);
    printf("%d",a[1].max);
    return 0;
}

P2146 软件包管理器

都说这题比较水,其实还是有点东西的,调了一下午…
才不是因为两个三目运算符嵌套太长了一直没看到错…
题目疯狂明示,n-1个关系画出来就是一棵树
用1表示已安装,0表示未安装,
就会发现安装就是对从根到当前节点的树链操作,卸载就是对当前节点的子树操作,具体操作是区间覆盖区间查询
很朴素的思路是在修改前后各查询一次,差值就是答案
然而仔细一想,对子树的查询得到的(1)已安装的个数,已经是答案了,用深度减去对树链的查询就是(0)未安装的个数
以下为坑点:
1、tag的初值为-1,因为0在本题有意义
2、tag只有在不等于-1的时候才能向下传
3、区间覆盖就是把+=改为=
4、习惯问题,节点右移

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
typedef unsigned long long ull;
int const maxn=1001100,maxm=1001100,inf=0x1f1f1f1f;
int n,q;
//***************************
struct E
{
	int to,next;
	E(int to=0,int next=0):
		to(to),next(next){}
}e[maxn];
int head[maxn],cnt;
void add(int u,int v)
{
	e[++cnt]=(E){v,head[u]};
	head[u]=cnt;
}
//***************************
int dep[maxn],size[maxn],hson[maxn],fa[maxn];
int id[maxn],top[maxn],tot;
int pre_dfs(int u,int f)
{
	dep[u]=dep[f]+1;
	size[u]=1;
	fa[u]=f;
	int maxson=-1;
	for(int i=head[u];i;i=e[i].next)
	{
		int v=e[i].to;
		if(v==f)
			continue;
		size[u]+=pre_dfs(v,u);
		if(maxson<size[v])
		{
			maxson=size[v];
			hson[u]=v;
		}
	}
	return size[u];
}
void mark_dfs(int u,int topf)
{
	id[u]=++tot;
	top[u]=topf;
	if(size[u]==1)
		return;
	mark_dfs(hson[u],topf);
	for(int i=head[u];i;i=e[i].next)
	{
		int v=e[i].to;
		if(!id[v])
			mark_dfs(v,v);
	}
}
//***************************
struct Tree
{
	int lc,rc,sum,tag;
}a[maxn<<1];
int t=1;
void pushup(int u)
{
	a[u].sum=a[a[u].lc].sum+a[a[u].rc].sum;
}
void pushdown(int u,int l,int r)
{
	int mid=(l+r)/2,
	lc=a[u].lc,rc=a[u].rc,tag=a[u].tag;
	a[lc].sum=tag*(mid-l+1);a[lc].tag=tag;
	a[rc].sum=tag*(r-mid);a[rc].tag=tag;
	a[u].tag=-1;
}
void build(int u,int l,int r)
{
	if(l==r)
	{
		a[u].tag=-1;
		return;
	}
	int mid=(l+r)/2;
	a[u].lc=++t;build(a[u].lc,l,mid);
	a[u].rc=++t;build(a[u].rc,mid+1,r);
}
void update(int u,int l,int r,int ll,int rr,int end)
{
	if(l==ll&&r==rr)
	{
//		printf("!%d %d %d\n",l,r,end);
		a[u].sum=end*(r-l+1);
		a[u].tag=end;
		return;
	}
	if(a[u].tag!=-1)
		pushdown(u,l,r);
	int mid=(l+r)/2;
	if(rr<=mid)
		update(a[u].lc,l,mid,ll,rr,end);
	else if(ll>mid)
		update(a[u].rc,mid+1,r,ll,rr,end);
	else
		update(a[u].lc,l,mid,ll,mid,end),update(a[u].rc,mid+1,r,mid+1,rr,end);
	pushup(u);
}
int query(int u,int l,int r,int ll,int rr)
{
	if(l==ll&&r==rr)
		return a[u].sum;
	if(a[u].tag!=-1)
		pushdown(u,l,r);
	int mid=(l+r)/2;
	return mid>=ll&&mid<rr?query(a[u].lc,l,mid,ll,mid)+query(a[u].rc,mid+1,r,mid+1,rr):(mid>=rr?query(a[u].lc,l,mid,ll,rr):query(a[u].rc,mid+1,r,ll,rr));
}
//***************************
int TL_query(int x)
{
	int ans=dep[x],y=1;
	while(top[x]!=top[y])
	{
//		printf("!!!%d %d\n",id[top[x]],id[x]);
		ans-=query(1,1,n,id[top[x]],id[x]);
		update(1,1,n,id[top[x]],id[x],1);
//		printf("??????%d %d %d\n",id[x],id[top[x]],query(1,1,n,id[top[x]],id[x]));
//		printf("~~~%d\n",query(1,1,n,7,7));
		x=fa[top[x]];
	}
	std::swap(x,y);
	ans-=query(1,1,n,id[x],id[y]);
//	printf("~~~%d\n",query(1,1,n,id[x],id[y]));
	update(1,1,n,id[x],id[y],1);
//	printf("!!!!!!%d %d %d\n",id[x],id[y],query(1,1,n,id[x],id[y]));
	return	ans;
}
int Tr_query(int x)
{
	int ans=query(1,1,n,id[x],id[x]+size[x]-1);
	update(1,1,n,id[x],id[x]+size[x]-1,0);
	return ans;
}
int main()
{
	scanf("%d",&n);
	for(int x,i=1;i<n;i++)
		scanf("%d",&x),add(x+1,i+1);
	pre_dfs(1,0);
	mark_dfs(1,1);
	build(1,1,n);
//	for(int i=1;i<=n;i++)
//		printf("!!!%d %d:%d %d\n",i,id[i],dep[i],top[i]);
	scanf("%d",&q);
	for(int x,i=1;i<=q;i++)
	{
		std::string op;
		std::cin>>op;
		scanf("%d",&x);x++;
//		printf("%c\n",op[0]);
		if(op[0]=='i')
			printf("%d\n",TL_query(x));
		else
			printf("%d\n",Tr_query(x));
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_40828060/article/details/83028157