• 「题解」:最近公共祖先


    问题 C: 最近公共祖先subset

    时间限制: 1 Sec  内存限制: 512 MB

    题面


    题面谢绝公开。

    题解


    什么是最近公共祖先?在一棵没有环的树上,每个节点肯定有其父亲节点和祖先节点。

    而最近公共祖先,就是两个节点在这棵树上深度最大的公共的祖先节点。

    于是我们考虑bfs预处理+倍增……

    以上都是扯淡。下面是真·题解

    考虑用线段树维护每一个点的答案。由于一个节点的权值只会对以它为根节点的子树中的节点答案有贡献,我们知道,一个子树的dfs序列一定是连续的。所以可以线段树维护,区间修改。

    对于每一次给点$x$染色,分部分考虑该点对整棵树的贡献:

    对于以该节点为根的子树:任意一个白点与该节点的公共祖先一定是这个点。所以可以直接用这个节点的权值去更新子树中节点的答案。

    特殊地,考虑该节点的父节点$y$。这其中属于$y$的子树而不属于$x$的子树的节点一定可以用其父节点的权值去更新。$y$与其父节点类似更新。

    另外,如果我更新到一个节点,当此节点已经用来更新过下面的信息时,可以停止更新。因为上层的节点一定已经被某个黑色节点下放过了。

    代码:

    #include<bits/stdc++.h>
    #define int long long
    #define rint register int
    using namespace std;
    inline void read(int &a)
    {
    	a=0;int b=1;char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')b=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){a=(a<<3)+(a<<1)+ch-'0';ch=getchar();}
    	a=a*b;return ;
    }
    int n,m,w[100005],f[100005];
    int v[200005],nxt[200005],first[100005],tot;
    int l[100005],r[100005],cnt;
    char str[35];
    bool vis[100005];
    struct node{int k,lz;}t[100005<<3];
    inline void add(int uu,int vv)
    {
    	v[++tot]=vv,nxt[tot]=first[uu];
    	first[uu]=tot;return ;
    }
    inline void dfs(int x,int fa)
    {
    	l[x]=++cnt;f[x]=fa;
    	for(rint i=first[x];i;i=nxt[i])
    		if(v[i]!=fa)dfs(v[i],x);
    	r[x]=cnt;return ;
    }
    inline void pushdown(int k)
    {
    	t[k<<1].k=max(t[k].lz,t[k<<1].k);
    	t[k<<1|1].k=max(t[k].lz,t[k<<1|1].k);
    	t[k<<1].lz=max(t[k].lz,t[k<<1].lz);
    	t[k<<1|1].lz=max(t[k].lz,t[k<<1|1].lz);
    	t[k].lz=0;return ;
    }
    inline void change(int k,int l,int r,int L,int R,int dat)
    {
    	if(L>R)return ;
    	pushdown(k);
    	if(L<=l&&r<=R)
    	{
    		t[k].k=max(t[k].k,dat);
    		t[k].lz=max(t[k].lz,dat);
    		return ;
    	}
    	int mid=(l+r)>>1;
    	if(L<=mid)change(k<<1,l,mid,L,R,dat);
    	if(R>mid)change(k<<1|1,mid+1,r,L,R,dat);
    	t[k].k=max(t[k<<1].k,t[k<<1|1].k);
    	return ;
    }
    inline int query(int k,int l,int r,int p)
    {
    	pushdown(k);
    	if(l==r)return t[k].k;
    	int mid=(l+r)>>1;
    	if(p<=mid)return query(k<<1,l,mid,p);
    	else return query(k<<1|1,mid+1,r,p);
    }
    signed main()
    {
    	//freopen("lca2.in","r",stdin);
    	//freopen("t3.out","w",stdout);
    	read(n),read(m);
    	for(rint i=1;i<=n;++i)read(w[i]);
    	for(rint i=1,ST,EN;i<n;++i)
    	{
    		read(ST),read(EN);
    		add(ST,EN),add(EN,ST);
    	}dfs(1,0);
    /*	for(rint i=1;i<=n;++i)
    		cout<<l[i]<<' '<<r[i]<<endl;*/
    	for(rint i=1,vi;i<=m;++i)
    	{
    		scanf("%s %lld",str,&vi);
    		if(str[0]=='M')
    		{
    			change(1,1,n,l[vi],r[vi],w[vi]);
    			vis[vi]=1;
    			int lc=l[vi],rc=r[vi],lin=0;vi=f[vi];
    			while(vi&&(!vis[vi]))
    			{
    				change(1,1,n,l[vi],lc-1,w[vi]);
    				change(1,1,n,rc+1,r[vi],w[vi]);
    				lc=l[vi];rc=r[vi];vi=f[vi];
    			}
    		}
    		else
    		{
    			int lin=query(1,1,n,l[vi]);
    			printf("%lld
    ",(lin==0)?-1:lin);
    		}
    	}
    	return 0;
    }
    /*
    7 7
    4 3 5 7 6 5 2
    1 4
    2 1
    7 5
    6 2
    2 5
    3 4
    Qu 1
    Mo 2
    Mo 4
    Qu 3
    Mo 2
    Mo 5
    Qu 6
    */
    
  • 相关阅读:
    思科、华为交换机链路聚合(LACP)配置实例
    华为交换机如何批量配置端口
    接口配置stp disable和配置stp edgedport enable有何区别
    上一篇下一篇文章链接添加TITLE属性
    GitHub打不开解决办法
    华为交换机和思科交换机生成树协议对接/替换方案
    vue中key的作用
    网络模块封装
    Typora+PicGo+LskyPro打造舒适写作环境
    C++ 类的静态成员
  • 原文地址:https://www.cnblogs.com/xingmi-weiyouni/p/11716369.html
Copyright © 2020-2023  润新知