有关dfs序的问题

链接:https://ac.nowcoder.com/acm/problem/13611

题目描述
shy有一颗树,树有n个结点。有k种不同颜色的染料给树染色。一个染色方案是合法的,当且仅当对于所有相同颜色的点对(x,y),x到y的路径上的所有点的颜色都要与x和y相同。请统计方案数。

dfs序:每个节点在dfs深度优先遍历中的进出栈的时间序列(为了方便接下来的操作我们往往有两种不同的写法,一种是只记录进栈顺序,一种是进栈出栈都记录,视题目的具体情况而定怎么写。)

一般来讲,我们需要的不仅仅有这个进出栈的顺序序列,还有每个点在第几个进栈这个信息——点 x 在第几个进栈就是这个点的时间戳,一般记为dfn[x] (时间戳在强连通分量tarjan算法里也有很巧妙的运用)。

正如图上所说,第二种dfs序两个相同数字之间就是这个点的子树,而其实在第一种方法中你也可以用个数组记录它出栈的之前最后一个进栈的点,也就是当前访问过的点里面时间戳最大的是哪一个,这样也可也得到这个点对应的子树是在哪一个区间里了。将来你就可以通过诸如在这个树上建线段树的操作实现对子树的一些修改的维护,比如说子树所有点的权值加一个数,就很美滋滋了(这个以后有机会再讲)。

稍微注意一点,在一般的树中(二叉树除外)一个节点的儿子是没有左右顺序的可以随便先访问哪个,所以,一棵树的dfs序是可能有很多种的。

如果我们用dfs序来表示这棵树,并且按dfs序来一个一个点涂色的话,我们就可以把问题从树上转化到链上,问题也许会简单许多。

我们会发现,如果我们按dfs序涂色,在涂每一个点之前,他的父亲祖父等祖先节点肯定都已经先涂过了(这些点的dfs序都比当前点小),他的兄弟节点(也包括各种或近或远的“堂兄弟”节点)和兄弟节点的子树也许也涂过一些。涂这个点无非是两种选择:涂一种新的颜色,或者涂一种已经用过的颜色。涂一种新的颜色自然是没用过的颜色都可以。而涂一种已经用过的颜色的话,这个点的颜色必须和他父亲的颜色一样,因为这个点到之前的所有点的路径都是要经过它父亲的,如果他和父亲不同色,他和他同色那个点的路径上就不可能所有点颜色都一样,至少他父亲就是不同的。也就是说涂一种已经用过的颜色其实只有一种方案——和父亲相同。

#include <bits/stdc++.h>
#define ll long long
using namespace std;
ll const maxn=3e2+5;
ll const mod=1e9+7;
ll n,k,ans,dp[maxn][maxn];
///dp[i][j] 表示从某个叶节点出发包括i个点  涂j种颜色
///涂同样的颜色只能跟父节点以上相同 所以为dp[i-1][j]
///涂不同的颜色可能从未涂过的颜色中选 所以为 (k-j+1)*dp[i-1][j-1]
int main(){
    cin>>n>>k;
    dp[0][0]=1;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=k;j++)
            dp[i][j]=(dp[i-1][j-1]*(k-j+1)+dp[i-1][j])%mod;
    for(int i=1;i<=k;i++)
    {ans+=dp[n][i];ans%=mod;}
    cout<<ans<<endl;
    return 0;
}

题目描述
现有一棵树。您需要写一个树上倍增算法,以实现如下操作:

A x 新建一个节点,将它作为x节点的儿子,编号为当前节点总数+1。
Q k p1 p2 p3.... 查询p1,p2,p3...这些节点的LCA。其中k表示查询节点的个数。
最初树上只有一个节点,编号为1。

这里有一个结论:多个节点的LCA,就是DFS序最大和最小的这两个节点的LCA。

因此 我们只需要将dfs序先求出来 直接找到其中最大最小的两个点的LCA就好

有人此时会有疑问 这个题目不是动态的嘛?

其实不影响的 先将整个树的DFS序求出来 然后再一个一个删点

链接:https://ac.nowcoder.com/acm/contest/33188/A

题目主要是让我们求长度为k-1的点集的最近公共祖先(一个点被删了),对于求多个点的最近公共祖先,我们并不真的要对所有点两两都求一次。我们只用取这些点中dfs序最小和最大的两个点来求最近公共祖先就行。

我写的代码通过率95 搞不懂哪里错了

#include<bits/stdc++.h>
using namespace std;
#define lowbit(x) x&(-x)
#define ll long long
const int maxn=1e5+5;
int n,k,cnta,cntb,maxa1,maxa2,mina1=1e9+7,mina2=1e9+7,maxb1,maxb2,minb1=1e9+7,minb2=1e9+7,sum;
int a[maxn],wa[maxn],wb[maxn],faa[maxn][25],fab[maxn][25],dfna[maxn],dfnb[maxn],rka[maxn],rkb[maxn];
int dpa[maxn],dpb[maxn];
vector<int>Qa[maxn],Qb[maxn];
void dfsa(int);
void dfsb(int); 
int lcaa(int,int);
int lcab(int,int);
int main(){
	cin>>n>>k;
	for(int i=1;i<=k;i++)scanf("%d",&a[i]);
	for(int i=1;i<=n;i++)scanf("%d",&wa[i]);
	for(int i=2;i<=n;i++)scanf("%d",&faa[i][0]),Qa[faa[i][0]].push_back(i);
	for(int i=1;i<=n;i++)scanf("%d",&wb[i]);
	for(int i=2;i<=n;i++)scanf("%d",&fab[i][0]),Qb[fab[i][0]].push_back(i);
	dfsa(1);dfsb(1);
	for(int i=1;i<=k;i++){
		if(dfna[a[i]]>=maxa1)maxa2=maxa1,maxa1=dfna[a[i]];
		else if(a[i]>maxa2)maxa2=dfna[a[i]];
		if(a[i]<=mina1)mina2=mina1,mina1=dfna[a[i]];
		else if(a[i]<mina2)mina2=dfna[a[i]];
		if(dfnb[a[i]]>=maxb1)maxb2=maxb1,maxb1=dfnb[a[i]];
		else if(a[i]>maxb2)maxb2=dfnb[a[i]];
		if(a[i]<=minb1)minb2=minb1,minb1=dfnb[a[i]];
		else if(a[i]<minb2)minb2=dfnb[a[i]];
	}
	for(int i=1;i<24;i++)
	for(int j=1;j<=n;j++)
	faa[j][i]=faa[faa[j][i-1]][i-1];
	for(int i=1;i<24;i++)
	for(int j=1;j<=n;j++)
	fab[j][i]=fab[fab[j][i-1]][i-1];
	for(int i=1;i<=k;i++){
	    int aa,bb,xx,yy;
		if(dfna[a[i]]==mina1)aa=mina2;
		else aa=mina1;
		if(dfna[a[i]]==maxa1)bb=maxa2;
		else bb=maxa1;
		if(dfnb[a[i]]==minb1)xx=minb2;
		else xx=minb1;
		if(dfnb[a[i]]==maxb1)yy=maxb2;
		else yy=maxb1;
		int LA=lcaa(rka[aa],rka[bb]),LB=lcab(rkb[xx],rkb[yy]);
		if(wa[LA]>wb[LB])
		sum++;
	}
	cout<<sum<<endl;
     return 0;
}
void dfsa(int u){
	dpa[u]=dpa[faa[u][0]]+1;
	dfna[u]=++cnta;rka[cnta]=u;
	for(int i=0;i<Qa[u].size();i++){
		int to=Qa[u][i];
		dfsa(to);
	}
}
void dfsb(int u){
	dpb[u]=dpb[fab[u][0]]+1;
	dfnb[u]=++cntb;rkb[cntb]=u;
	for(int i=0;i<Qb[u].size();i++){
		int to=Qb[u][i];
		dfsb(to);
	}
}
int lcaa(int u,int v){
	if(dpa[u]<dpa[v])swap(u,v);
	for(int i=23;i>=0;i--)
	if(dpa[faa[u][i]]>=dpa[v])u=faa[u][i];
	if(u==v)return u;
	for(int i=23;i>=0;i--)
	if(faa[u][i]!=faa[v][i])u=faa[u][i],v=faa[v][i];
	return faa[u][0];
}
int lcab(int u,int v){
	if(dpb[u]<dpb[v])swap(u,v);
	for(int i=23;i>=0;i--)
	if(dpb[fab[u][i]]>=dpb[v])u=fab[u][i];
	if(u==v)return u;
	for(int i=23;i>=0;i--)
	if(fab[u][i]!=fab[v][i])u=fab[u][i],v=fab[v][i];
	return fab[u][0];
}

correct code:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double db;
typedef pair <int, int> PII;
typedef unsigned long long ull;
const double pi=acos(-1.0);
const long long inf=0x3f3f3f3f3f3f3f3f;
const double epsn=1e-9;
const ll modp=1e9+7;
const int maxn=1e5+5;

ll a[maxn];
int f[maxn][30],dep[maxn],dfn[maxn];ll va[maxn];
int p[2][maxn],n,k;
vector<int> g[maxn];
int cnt=0;
void dfs(int u,int fa){
	f[u][0]=fa;
	dep[u]=dep[fa]+1;
	cnt++;
	dfn[u]=cnt;
	for(int i=1;(1<<i)<=dep[u];i++){
		f[u][i]=f[f[u][i-1]][i-1];
	}
	for(auto i:g[u]){
		if(i==fa)continue;
		dfs(i,u);
	}
}

int lca(int u,int v){
	if(dep[u]<dep[v]){int t=u;u=v;v=t;}
	for(int i=log2(dep[u]-dep[v]);i>=0;i--){
		if(dep[f[u][i]]>=dep[v])u=f[u][i];
	}
	if(u==v)return u;
	
	for(int i=log2(dep[u]);i>=0;i--){
		if(f[u][i]!=f[v][i]){
			u=f[u][i];v=f[v][i];
		}
	}
	return f[u][0];
}
bool cmp(int a,int b){
	return dfn[a]<dfn[b];
}
void solve(int temp){
	for(int i=1;i<=n;i++){
		cin>>va[i];
		g[i].clear();
	}
	for(int i=2;i<=n;i++){
		int x;cin>>x;g[x].push_back(i);
	}
	cnt=0;
	dfs(1,0);
	sort(a+1,a+1+k,cmp);
	int x=lca(a[2],a[k]);p[temp][a[1]]=va[x];
	x=lca(a[1],a[k-1]);p[temp][a[k]]=va[x];
	x=lca(a[1],a[k]);
	for(int i=2;i<=k-1;i++){
	    p[temp][a[i]]=va[x];
	}
}
int main()
{
	cin>>n>>k;
	for(int i=1;i<=k;i++)cin>>a[i];
	solve(0);solve(1);
	int ans=0;
	for(int i=1;i<=k;i++){
		if(p[0][a[i]]>p[1][a[i]])ans++;
	}
	cout<<ans;
}
posted @ 2022-07-31 15:27  wzx_believer  阅读(31)  评论(0编辑  收藏  举报