牛客北京信息科技大学(同步赛)J 芭芭拉冲鸭~(续)

继树剖之后,lca可以用树剖球了!。

题目询问树内两个点之间的信息,我们想到两个点连成的链可以通过以1为根的链到x的值+y的值减去2*lca(x,y).维护一个26的数组存一下a-z,然后计算即可

//#pragma GCC optimize(3)
#include <bits/stdc++.h>
#define debug(x) cout<<#x<<":"<<x<<endl;
//#define _CRT_SECURE_NO_WARNINGS
typedef  long long ll;
using namespace std;
#define rep(i,j,n) for(ll i=j;i<=n;i++)
#define per(i,j,n) for(ll i=j;i>=n;i--)
typedef unsigned long long ull;
typedef unsigned short us;
const ll INF= 1e18+7;
const ll maxx = 2e5+700;
ll mod;
const double eps=1e-8;
inline bool read(ll &num){char in;bool IsN=false;in=getchar();if(in==EOF) return false;while(in!='-'&&(in<'0'||in>'9')) in=getchar();if(in=='-'){ IsN=true;num=0;}else num=in-'0';while(in=getchar(),in>='0'&&in<='9'){num*=10,num+=in-'0';}if(IsN) num=-num;return true;}
ll n,m;
ll fa[maxx],deep[maxx],size[maxx],son[maxx];
struct stu
{
    ll to,next;
}A[maxx*2];
ll head[maxx],cnt=0;
ll top[maxx],id[maxx],a[maxx];
char ch[maxx];
ll num=0;
ll sum[maxx][28];
ll zhi[30];
void add(ll u,ll v)
{
    A[cnt].to=v;
    A[cnt].next=head[u];
    head[u]=cnt++;
}

void dfs1(ll now,ll f)
{
    ll k=0;
    fa[now]=f;size[now]=1;
    deep[now]=deep[f]+1;
    sum[now][(ll)(ch[now]-'a'+1) ]++;
    if(now!=1)
    {
        rep(i,1,26)
        sum[now][i]+=sum[f][i];
    }
    for(ll i=head[now];~i;i=A[i].next)
    {
        if(A[i].to!=f)
        {
            dfs1(A[i].to,now);
            size[now]+=size[A[i].to];
            if(size[A[i].to]>k)
            {
                k=size[A[i].to];
                son[now]=A[i].to;
            }
        }
    }
}

void dfs2(ll now,ll f)
{
    top[now]=f;
    id[now]=++num;
    //wt[id[now]] = a[now];
    if(son[now]==0) return ; // 没有儿子了
    dfs2(son[now],f);
    for(ll i=head[now];~i;i=A[i].next)
    {
         if(A[i].to!=fa[now]&&A[i].to!=son[now])
         {
            dfs2(A[i].to,A[i].to);
         }
    }
}
ll lca(ll x,ll y)
{
    while(top[x]!=top[y])
    {
        // x shen
        if(deep[top[x]]<=deep[top[y]] ) swap(x,y);
        x=fa[x];
    }
    if(deep[x]<deep[y])
    return x;
    else return y;
}
int main()
{
    ll t;
    ll r;
    rep(i,1,maxx-1) head[i]=-1;

    cin>>n;

    rep(i,1,n-1)
    {
        ll x,y;
        scanf("%lld%lld",&x,&y);
        add(x,y);
        add(y,x);
    }
    scanf("%s",ch+1);
    dfs1(1,0);
    dfs2(1,1);

    cin>>m;
    rep(i,1,m)
    {
        ll x,y;
        scanf("%lld%lld",&x,&y);
        ll lc=lca(x,y);
        ll f=0;
        ll ans=0;
        rep(j,1,26) zhi[j]=0;
        zhi[(ll)(ch[lc]-'a'+1)]++;
        rep(j,1,26)
        {
            zhi[j]+=sum[x][j];
            zhi[j]+=sum[y][j];
            zhi[j]-=2*sum[lc][j];
            if(zhi[j]%2==1){
                ans+=(zhi[j]-1);
                f=1;
            }
            else ans+=zhi[j];
        }
        printf("%lld\n",ans+f);
        //printf("%lld \n",lca(x,y));
    }
    return 0;
}
/*
6 1000
1 2
1 3
3 4
3 5
5 6

*/




  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值