题意:一颗树,每条边有个颜色,一条路径被定义为“彩虹”,当且仅当其上没有长度大于等于2的同色子路径。一个结点被定义为“超级结点”,当且仅当从其发出的所有路径都是“彩虹”。
枚举所有长度为2,且同色的路径,其两端点方向发出的子树中的结点都不可能成为答案,只需要将它们覆盖掉即可,用dfs序处理,在左端点+1,右端点-1,最后求个前缀和,为0的结点就是没有被覆盖过的结点,也即“超级结点”。
分两种情况:这两条边深度相同;这两条边深度不同。
#include<cstdio> #include<map> #include<vector> #include<algorithm> using namespace std; int n; int c[50005],Map[50005]; int fa[50005],first[50005],nex[100005],v[100005],e,Ls[50005],Rs[50005],tot,w[100005]; int fav[50005]; void AddEdge(int U,int V,int W){ v[++e]=V; w[e]=W; nex[e]=first[U]; first[U]=e; } void df1(int U){ Ls[U]=++tot; Map[tot]=U; for(int i=first[U];i;i=nex[i]){ if(!fa[v[i]]){ fa[v[i]]=U; fav[v[i]]=w[i]; df1(v[i]); } } Rs[U]=tot; } void fugai(int L,int R){ ++c[L]; if(R!=n){ --c[R+1]; } } void fugai2(int L,int R){ if(L!=1){ ++c[1]; --c[L]; } if(R!=n){ ++c[R+1]; } } void dfs(int U){ for(int i=first[U];i;i=nex[i]){ if(fa[v[i]]==U){ if(U!=1 && fav[U]==w[i]){ fugai(Ls[v[i]],Rs[v[i]]); fugai2(Ls[U],Rs[U]); } dfs(v[i]); } } } void df2(int U){ map<int,int>cnts; for(int i=first[U];i;i=nex[i]){ if(fa[v[i]]==U){ ++cnts[w[i]]; } } for(int i=first[U];i;i=nex[i]){ if(fa[v[i]]==U){ if(cnts[w[i]]>1){ fugai(Ls[v[i]],Rs[v[i]]); } df2(v[i]); } } } int main(){ //freopen("g.in","r",stdin); scanf("%d",&n); int x,y,z; for(int i=1;i<n;++i){ scanf("%d%d%d",&x,&y,&z); AddEdge(x,y,z); AddEdge(y,x,z); } fa[1]=-1; df1(1); dfs(1); df2(1); vector<int>vs; for(int i=1;i<=n;++i){ c[i]+=c[i-1]; //printf("%d ",c[i]); if(!c[i]){ vs.push_back(Map[i]); } } //puts(""); printf("%d ",vs.size()); sort(vs.begin(),vs.end()); for(vector<int>::iterator it=vs.begin();it!=vs.end();++it){ printf("%d ",*it); } return 0; }