E. Milk Visits

E. Milk Visits

https://codeforces.com/group/5yyKg9gx7m/contest/269717/problem/E

题目描述:

农夫约翰计划建造N(1≤N≤105)个农场,这些农场将通过N-1条道路连接起来,形成一棵树(即,所有农场彼此之间都是可到达的,没有循环)。 每个农场都有一头母牛,其品种为h或g。

农夫约翰的M个朋友(1≤M≤105)常来拜访他。 在与朋友i进行访问期间,农夫约翰将与他的朋友一起沿着从农场Ai到农场Bi的独特道路行走(可能是Ai = Bi)。 此外,他们可以沿行进路线尝试从任何母牛身上获取牛奶。 由于约翰农民的大多数朋友也是农民,因此他们对牛奶有很强的偏好。 他的一些朋友只会喝g牛奶,其余的朋友只会喝h牛奶。 只有农夫约翰的朋友们在参观期间可以喝自己喜欢的牛奶,他们才会高兴。

分析:

先构造出树,可以看出,从x到y的路上一定经过他们的公共祖先。h[i]记录为他从最顶端的根r到i的h牛奶的多少,同理g[i]表示g牛奶。

用倍增求lca,如果只考虑h牛奶,可以看出x到y路上h牛奶的多少为h[x]+h[y]-h[lca]-h[fa[lca]],其中要包含lca的点。g也是同理。

至于要建立树,因为双向图,可以用2个vector分别表示x,y的儿子节点。再dfs遍历树时从人一点出发(下面从点1),每个节点访问一次。也可以遍历完树。

代码:

#include<vector> 
#include<algorithm>
#include<cstring>
#include<iostream>
#include<cmath>
using namespace std;
typedef long long ll;
const int N=1e5+6;
vector<int> son[N];
int dep[N],fa[N][30];
int h[N],g[N];
int n,m;
char s[N];
bool vis[N];
void dfs(int prev,int rt)
{
    //遍历树,预处理从rt上移情况 
    vis[rt]=1;    
    dep[rt]=dep[prev]+1;
    fa[rt][0]=prev;
    h[rt]+=h[prev];
    g[rt]+=g[prev];
    for(int i=1;i<25;i++)
        fa[rt][i]=fa[fa[rt][i-1]][i-1];
    for(int i=0;i<son[rt].size();i++)
    {
        if(!vis[son[rt][i]]) 
        dfs(rt,son[rt][i]);
    }
}
int LCA(int x,int y)
{
    if(dep[x]<dep[y]) swap(x,y);
    for(int i=24;i>=0;i--) 
        if(dep[x]-(1<<i)>=dep[y]) x=fa[x][i];
    if(x==y) return x;
    for(int i=24;i>=0;i--)
        if(fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];
    return fa[x][0];
}
int main()
{
    cin>>n>>m;
    cin>>s;
    for(int i=0;i<=n;i++) son[i].clear();
    memset(vis,0,sizeof vis);
    for(int i=1;i<=n;i++)
    {
        if(s[i-1]=='H')    h[i]=1,g[i]=0;
        else    h[i]=0,g[i]=1;
    }
    for(int i=1;i<n;i++)
    {
        int a,b;
        scanf("%d%d",&a,&b);
        son[a].push_back(b);
        son[b].push_back(a);
    }
    dep[0]=-1;
    dfs(0,1);
    char ans[m+6];
    for(int i=0;i<m;i++)
    {
        int x,y;
        char c;
        scanf("%d %d %c",&x,&y,&c);
        int lca=LCA(x,y);
        if(c=='H')
        {
            if(h[x]+h[y]-h[lca]-h[fa[lca][0]]!=0)
            ans[i]='1';
            else ans[i]='0';
        }
        else
        {
            if(g[x]+g[y]-g[lca]-g[fa[lca][0]]!=0)
            ans[i]='1';
            else ans[i]='0';
        }    
    }
    ans[m]='\0';
    printf("%s\n",ans);
    return 0;
}

 

posted on 2020-03-10 21:50  Aminers  阅读(137)  评论(0编辑  收藏  举报

导航