您的位置:首页 > Web前端

CF764 C. Timofey and a tree(dfs序+线段树)

2017-02-03 09:34 381 查看
传送门

题目大意:给一棵树,树上每个节点都有颜色,现在要求将某一个点变成根,使得每个子树上的所有点颜色相同,(根的颜色可不管,根的子树与子树间颜色可不同,但同一个 子树颜色必须相同)问能否找到这样的点,若有则输出这个点。

解题思路1:换根,就想到了BZOJ3306,百度了一份代码直接在这上面改。

                   将每一个点都遍历一遍把它变作根,然后遍历它的子树的最大值以及最小值,若两者相等则是符合要求。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
int read()
{
int x=0,f=1;
char ch=getchar();
while (ch<'0' || ch>'9')
{
if (ch=='-') f=-1;
ch=getchar();
}
while (ch>='0' && ch<='9')
{
x=x*10+ch-'0';
ch=getchar();
}
return x*f;
}
#define MAXN 200010
int N,Q,val[MAXN];
struct EdgeNode
{
int next,to;
} edge[MAXN<<1];
int head[MAXN],cnt;
void AddEdge(int u,int v)
{
cnt++;
edge[cnt].next=head[u];
head[u]=cnt;
edge[cnt].to=v;
}
void InsertEdge(int u,int v)
{
if (u==0) return;
AddEdge(u,v);
AddEdge(v,u);
}
int pl[MAXN],dfn,pr[MAXN],dfsn[MAXN],deep[MAXN],father[MAXN][21],root;
void DFS(int now,int last)
{
pl[now]=++dfn;
dfsn[dfn]=now;
for (int i=1; i<=20; i++)
if (deep[now]>=(1<<i))
father[now][i]=father[father[now][i-1]][i-1];
else
break;
for (int i=head[now]; i; i=edge[i].next)
if (edge[i].to!=last)
{
deep[edge[i].to]=deep[now]+1;
father[edge[i].to][0]=now;
DFS(edge[i].to,now);
}
pr[now]=dfn;
}
int LCA(int x,int y)
{
if (deep[x]<deep[y]) swap(x,y);
int dd=deep[x]-deep[y];
for (int i=0; i<=20; i++)
if (dd&(1<<i)) x=father[x][i];
for (int i=20; i>=0; i--)
if (father[x][i]!=father[y][i])
x=father[x][i],y=father[y][i];
if (x==y) return x;
else return father[x][0];
}
struct SegmentTreeNode
{
int l,r,minn,mx;
} tree[MAXN<<2];
inline void Update(int now)
{
tree[now].minn=min(tree[now<<1].minn,tree[now<<1|1].minn);
tree[now].mx=max(tree[now<<1].mx,tree[now<<1|1].mx);
}
void BuildTree(int now,int l,int r)
{
tree[now].l=l;
tree[now].r=r;
if (l==r)
{
tree[now].minn=tree[now].mx=val[dfsn[l]];
return;
}
int mid=(l+r)>>1;
BuildTree(now<<1,l,mid);
BuildTree(now<<1|1,mid+1,r);
Update(now);
}

int Query(int now,int L,int R)
{
if (R<L) return 0x7fffffff;
int l=tree[now].l,r=tree[now].r;
if (L==l && R==r) return tree[now].minn;
int mid=(l+r)>>1,re=0x7fffffff;
if (R<=mid) return Query(now<<1,L,R);
else if (L>mid) return Query(now<<1|1,L,R);
else return min(Query(now<<1,L,mid),Query(now<<1|1,mid+1,R));
return re;
}
void ChangeRoot(int x)
{
root=x;
}
int GetAns(int x)
{
int lca=LCA(root,x);
if (x==root) return Query(1,1,N);
if (pl[x]<=pl[root] && pr[x]>=pr[root])
{
int dd=deep[root]-deep[x]-1,y=root;
for (int i=0; i<=20; i++)
if (dd&(1<<i)) y=father[y][i];
return min(Query(1,1,pl[y]-1),Query(1,pr[y]+1,dfn));
}
return Query(1,pl[x],pr[x]);
}

int Query1(int now,int L,int R)
{
if (R<L) return -1;
int l=tree[now].l,r=tree[now].r;
if (L==l && R==r) return tree[now].mx;
int mid=(l+r)>>1,re=-1;
if (R<=mid) return Query1(now<<1,L,R);
else if (L>mid) return Query1(now<<1|1,L,R);
else return max(Query1(now<<1,L,mid),Query1(now<<1|1,mid+1,R));
return re;
}

int GetAns1(int x)
{
int lca=LCA(root,x);
if (x==root) return Query1(1,1,N);
if (pl[x]<=pl[root] && pr[x]>=pr[root])
{
int dd=deep[root]-deep[x]-1,y=root;
for (int i=0; i<=20; i++)
if (dd&(1<<i)) y=father[y][i];
return max(Query1(1,1,pl[y]-1),Query1(1,pr[y]+1,dfn));
}
return Query1(1,pl[x],pr[x]);
}

int main()
{
N=read();
for (int fa,son,i=1; i<N; i++) fa=read(),son = read(),InsertEdge(fa,son);
for(int i=1; i<=N; i++) val[i]=read();
DFS(1,0);
root=1;
BuildTree(1,1,dfn);
//int flag = 0;
int flag;
for(int i=1; i<=N; i++)
{
int x = i;
ChangeRoot(x);
flag = 1;
for(int i=head[x]; i; i=edge[i].next)
{
int v = edge[i].to;
if(v==x)continue;
int a = GetAns(v);
//a = min(a,val[v]);
int b = GetAns1(v);
//b = max(b,val[v]);
if(a!=b)
{
flag = 0;
break;
}
//printf("%d %d %d\n",x,a,b);
}
if(flag)
{
printf("YES\n%d\n",x);
break;
}
}
if(!flag)
{
printf("NO\n");
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: