zoukankan      html  css  js  c++  java
  • P4315 月下“毛景树” 题解

    P4315 月下“毛景树” 题解

    题目链接

    这道题目是比较裸的树剖+线段树题目,只不过有一些细节需要注意。

    首先,这道题目是边权,所以我们要转成点权,因为每一条边都对应它下面的一个点,所以我们用它下面点的权值来代替边权。

    然后在线段树处理链顶边界的时候,左区间要+1

    (like this)

        query(1,1,n,l+1,r);
    

    原理:处理链顶时是在重链上,根据dfs_2的遍历顺序,所以当前区间+1肯定就是重儿子

    但是这样就会出现一个问题,看下面这种情况

    很明显查询1-2这条链的时候,最后都跳到了1,如果左区间再加1的线段树就会无限递归,所以这里也要特判一下。

    	if (l+1>r) return maxx;
    	else return max(maxx,query(1,1,n,l+1,r));
    

    关于线段树标记的下传

    有两种下传方法:

    1. 先下传加,再下传覆盖
      这样下传就不能分清当前覆盖究竟是在加之前还是之后
    2. 先下传覆盖,同时将儿子的加清零,这样就不会有上面的烦恼,update要在打覆盖标记的时候把加标记清零
        t[ls].add=t[rs].add=0;
    

    代码

    // luogu-judger-enable-o2
    #include<iostream>
    #include<cstdio>
    #define pii pair<int,int>
    #define mp make_pair
    #define one first
    #define two second
    using namespace std;
    const int N=1e5+100;
    struct Tree{
    	int ls,rs,maxx,add,fix;
    }t[N<<1];
    struct edge{
    	int s,e,v,net;
    }ed[N<<1];
    int n,tot,idx,cnt=1;
    int head[N],w[N],father[N],son[N],size[N],top[N],deep[N],id[N],fv[N];
    pii p[N];
    inline void push_up(int rt)
    {
    	t[rt].maxx=max(t[t[rt].ls].maxx,t[t[rt].rs].maxx);
    	return ;
    }
    inline void push_down(int rt,int l,int r)
    {
    	int ls=t[rt].ls,rs=t[rt].rs;
    	if (t[rt].fix!=-1)
    	{
    		int k=t[rt].fix;
    		t[ls].fix=k;
      		t[ls].maxx=k;
    		t[rs].fix=k;
    		t[rs].maxx=k;
    		t[rt].fix=-1;
    		t[ls].add=t[rs].add=0;
    	}
    	if (t[rt].add)
    	{
    		int k=t[rt].add;
    		t[ls].add+=k;
    		t[ls].maxx+=k;
    		t[rs].add+=k;
    		t[rs].maxx+=k;
    		t[rt].add=0;
    	}
    	return ;
    }
    inline int query(int rt,int l,int r,int nl,int nr)
    {
    	if (l==nl&&r==nr) return t[rt].maxx;
    	int mid=(l+r)>>1;
    	push_down(rt,l,r);
    	if (nr<=mid) return query(t[rt].ls,l,mid,nl,nr);
    	else if (nl>mid) return query(t[rt].rs,mid+1,r,nl,nr);
    	else return max(query(t[rt].ls,l,mid,nl,mid),query(t[rt].rs,mid+1,r,mid+1,nr));
    }
    inline void update(int rt,int l,int r,int nl,int nr,int opt,int k)
    {
    	if (l==nl&&r==nr)
    	{
    		if (opt==1)
    		{
    			t[rt].add+=k;
    			t[rt].maxx+=k;
    		}
    		if (opt==2)
    		{
    			t[rt].fix=k;
    			t[rt].maxx=k;
    			t[rt].add=0;
    		}
    		return ;
    	}
    	int mid=(l+r)>>1;
    	push_down(rt,l,r);
    	if (nr<=mid) update(t[rt].ls,l,mid,nl,nr,opt,k);
    	else if (nl>mid) update(t[rt].rs,mid+1,r,nl,nr,opt,k);
    	else
    	{
    		update(t[rt].ls,l,mid,nl,mid,opt,k);
    		update(t[rt].rs,mid+1,r,mid+1,nr,opt,k);
    	}
    	push_up(rt);
    	return ;
    }
    inline void update_link(int x,int y,int opt,int k)
    {
    	while (top[x]!=top[y])
    	{
    		if (deep[top[x]]>deep[top[y]]) swap(x,y);
    		update(1,1,n,id[top[y]],id[y],opt,k);
    		y=father[top[y]];
    	}
    	int l=id[x],r=id[y];
    	if (l>r) swap(l,r);
    	if (l+1>r) return ;
    	update(1,1,n,l+1,r,opt,k);
    	return ;
    }
    inline int query_link(int x,int y)
    {
    	int maxx=0;
    	while (top[x]!=top[y])
    	{
    		if (deep[top[x]]>deep[top[y]]) swap(x,y);
    		maxx=max(query(1,1,n,id[top[y]],id[y]),maxx);
    		y=father[top[y]];
    	}
    	int l=id[x],r=id[y];
    	if (l>r) swap(l,r);
    	if (l+1>r) return maxx;
    	else return max(maxx,query(1,1,n,l+1,r));
    }
    inline void dfs_2(int x,int tp)
    {
    	id[x]=++idx;
    	w[idx]=fv[x];
    	top[x]=tp;
    	if (son[x]) dfs_2(son[x],tp);
    	for (int i=head[x];i;i=ed[i].net)
    	if (ed[i].e!=father[x]&&ed[i].e!=son[x])
    	dfs_2(ed[i].e,ed[i].e);
    	return ;
    }
    inline void dfs_1(int x,int fa)
    {
    	deep[x]=deep[fa]+1;
    	father[x]=fa;
    	size[x]=1;
    	for (int i=head[x];i;i=ed[i].net)
    	if (ed[i].e!=fa)
    	{
    		dfs_1(ed[i].e,x);
    		size[x]+=size[ed[i].e];
    		if (size[son[x]]<size[ed[i].e])
    		son[x]=ed[i].e;
    	}
    	else fv[x]=ed[i].v;
    	return ;
    }
    inline void build(int rt,int l,int r)
    {
    	t[rt].fix=-1;
    	t[rt].add=0;
    	if (l==r)
    	{
    		t[rt].maxx=w[l];
    		return ;
    	}
    	int mid=(l+r)>>1;
    	t[rt].ls=++cnt;
    	build(t[rt].ls,l,mid);
    	t[rt].rs=++cnt;
    	build(t[rt].rs,mid+1,r);
    	push_up(rt);
    	return ;
    }
    inline void add(int s,int e,int v)
    {
    	ed[++tot]=(edge){s,e,v,head[s]};
    	head[s]=tot;
    	return ;
    }
    int main()
    {
    	scanf("%d",&n);
    	for (int i=1;i<=n-1;i++)
    	{
    		int s,e,v;
    		scanf("%d%d%d",&s,&e,&v);
    		p[i]=mp(s,e);
    		add(s,e,v);add(e,s,v);
    	}
    	dfs_1(1,0);
    	dfs_2(1,1);
    	build(1,1,n);
    	while (1)
    	{
    		char ss[15];
    		int u,v,w,k;
    		scanf("%s",ss+1);
    		if (ss[1]=='S') return 0;
    		if (ss[2]=='h')
    		{
    			scanf("%d%d",&k,&w);
    			int x=p[k].one,y=p[k].two;
    			if (deep[x]>deep[y]) swap(x,y);
    			update(1,1,n,id[y],id[y],2,w);
    		}
    		if (ss[2]=='o')
    		{
    			scanf("%d%d%d",&u,&v,&w);
    			update_link(u,v,2,w);
    		}
    		if (ss[1]=='A')
    		{
    			scanf("%d%d%d",&u,&v,&w);
    			update_link(u,v,1,w);
    		}
    		if (ss[1]=='M')
    		{
    			scanf("%d%d",&u,&v);
    			printf("%d
    ",query_link(u,v));
    		}
    	}
    	return 0;
    }
    

    收获:线段树在下传标记的时候一定要考虑怎样下传才不会相互影响,或者直接打时间戳

  • 相关阅读:
    为什么要对url进行encode
    活在当下
    Linux Shell 文本处理工具
    Servlet、Servlet容器等内容讲解
    Java编程中的一些常见问题汇总
    创建文件目录
    ubuntu
    iptables
    mysqldump导入导出
    pt-table-sync
  • 原文地址:https://www.cnblogs.com/last-diary/p/11411563.html
Copyright © 2011-2022 走看看