ABCAB

题目链接

题解链接

题意:给你一棵树,让你输出节点u到v的最短路径上子序列ABCAB的个数;

思路:我们建立树上可持续化线段树,那么这颗树的叶子节点上的那颗线段树就保存了这条链的消息,对于两个节点,之间的ABCAB的个数,就等于第u个节点的线段树dep【lca】到dep【u】的区间和加第v颗线段树dep【lca】到dep【v】的区间和的和。需要注意的是位于左边的那条链的答案需要反着求。

#include<bits/stdc++.h>
using namespace std;
const int maxn=3e4+10,mod=10007;
char a[maxn];
int f[maxn][20],dep[maxn],rt[maxn],n,cnt,ls[maxn*20],rs[maxn*20];
struct node{
    int cat, A, AB, ABC, ABCB, B, BC, BCB, BCBA, C, CB, CBA, BA;
    node operator+(const node &t) const {
        node tmp;
        tmp.cat = (cat + t.cat + A * t.BCBA + AB * t.CBA + ABC * t.BA + ABCB * t.A) % mod;
        tmp.A = (A + t.A) % mod;
        tmp.AB = (AB + t.AB + A * t.B) % mod;
        tmp.ABC = (ABC + t.ABC + A * t.BC + AB * t.C) % mod;
        tmp.ABCB = (ABCB + t.ABCB + A * t.BCB + AB * t.CB + ABC * t.B) % mod;
        tmp.B = (B + t.B) % mod;
        tmp.BC = (BC + t.BC + B * t.C) % mod;
        tmp.BCB = (BCB + t.BCB + B * t.CB + BC * t.B) % mod;
        tmp.BCBA = (BCBA + t.BCBA + B * t.CBA + BC * t.BA + BCB * t.A) % mod;
        tmp.C = (C + t.C) % mod;
        tmp.CB = (CB + t.CB + C * t.B) % mod;
        tmp.CBA = (CBA + t.CBA + C * t.BA + CB * t.A) % mod;
        tmp.BA = (BA + t.BA + B * t.A) % mod;
        return tmp;
    }
}tr[maxn*20];
vector<int>G[maxn];
#define mid (l+r)/2
void up(int& o,int pre,int l,int r,int p,char c)
{
    o=++cnt;
    ls[o]=ls[pre];
    rs[o]=rs[pre];
    if(l==r)
    {
        if(c=='A')
            tr[o].A = 1;
        else if(c=='B')
            tr[o].B =1;
        else if(c=='C')
            tr[o].C =1;
        return ;
    }
    if(p<=mid)up(ls[o],ls[pre],l,mid,p,c);
    else up(rs[o],rs[pre],mid+1,r,p,c);
    tr[o]=tr[ls[o]] + tr[rs[o]];
}
 
void dfs(int u,int fa)
{
    f[u][0]=fa;
    dep[u]=dep[fa]+1;
    for(int i=1;i<18;i++)
    {
        f[u][i]=f[f[u][i-1]][i-1];
    }
    up(rt[u],rt[fa],1,n,dep[u],a[u]);
    for(int i=0;i<G[u].size();i++)
    {
        int v=G[u][i];
        if(v==fa)continue;
        dfs(v,u);
    }
}
node qu(int o,int l,int r,int L,int R)
{
    if(l>=L&&r<=R)return tr[o];
    if(R<=mid)return  qu(ls[o],l,mid,L,R);
    if(L>mid)return qu(rs[o],mid+1,r,L,R);
    else return qu(ls[o],l,mid,L,R) + qu(rs[o],mid+1,r,L,R);
}
int Lca(int u,int v)
{
    if(dep[u]<dep[v])swap(u,v);
    assert(dep[u] >= dep[v]);
    for(int i=17;~i;i--)
    {
        if(dep[f[u][i]]>=dep[v])u=f[u][i];
    }
    assert(dep[v]==dep[u]);
    if(u==v)return u;
    for(int i=17;~i;i--)
    {
        if(f[u][i]!=f[v][i])
        {
            u=f[u][i];
            v=f[v][i];
        }
    }
    return f[u][0];
}
int main()
{
    int q;
    scanf("%d %d",&n,&q);
    scanf("%s",a+1);
    for(int i=1;i<n;i++)
    {
        int u,v;
        scanf("%d%d",&u,&v);
        G[u].push_back(v);
        G[v].push_back(u);
    }
    dfs(1,0);
    while(q--)
    {
        int u,v;
        scanf("%d %d",&u,&v);
        int lca=Lca(u,v);
        if(u==lca||v==lca)
        {
            node an;
            if(u==lca)swap(u,v);
            an=qu(rt[u],1,n,dep[v],dep[u]);
            cout<<an.cat%mod<<'\n';
        }
        else
        {
            int ans;
            node t1=qu(rt[u],1,n,dep[lca],dep[u]);
            node t2=qu(rt[v],1,n,dep[lca]+1,dep[v]);
            ans = (t1.cat + t2.cat + t1.A * t2.BCBA + t1.BA * t2.CBA + t1.CBA * t2.BA + t1.BCBA * t2.A) % mod;
            printf("%d\n",ans);
        }
    }
 }

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值