loj2065 「SDOI2016」模式字符串

ref不是太懂

#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
typedef unsigned long long ull;
int T, n, m, hea[1000005], cnt, uu, vv, rnd[1000005], rot, siz[1000005];
int tot, sf[1000005], sg[1000005], ff[1000005], gg[1000005];
ull bse[1000005], hs1[1000005], hs2[1000005], ans;
char ss[1000005], tt[1000005];
bool vis[1000005];
struct Edge{
    int too, nxt;
}edge[2000005];
void rn(int &x){
    char ch=getchar();
    x = 0;
    while(ch<'0' || ch>'9') ch = getchar();
    while(ch>='0' && ch<='9'){
        x = x * 10 + ch - '0';
        ch = getchar();
    }
}
void add_edge(int fro, int too){
    edge[++cnt].nxt = hea[fro];
    edge[cnt].too = too;
    hea[fro] = cnt;
}
void getRoot(int x, int f){
    rnd[x] = 0;
    siz[x] = 1;
    for(int i=hea[x]; i; i=edge[i].nxt){
        int t=edge[i].too;
        if(!vis[t] && t!=f){
            getRoot(t, x);
            siz[x] += siz[t];
            rnd[x] = max(rnd[x], siz[t]);
        }
    }
    rnd[x] = max(rnd[x], tot-siz[x]);
    if(rnd[x]<rnd[rot]) rot = x;
}
int dfs(int x, int f, int d, ull hx){
    siz[x] = 1;
    hx = hx * 131 + ss[x];
    if(hs1[d]==hx){
        ff[(d-1)%m+1]++;
        ans += sg[m-(d-1)%m];
    }
    if(hs2[d]==hx){
        gg[(d-1)%m+1]++;
        ans += sf[m-(d-1)%m];
    }
    int tmp=1;
    for(int i=hea[x]; i; i=edge[i].nxt){
        int t=edge[i].too;
        if(!vis[t] && t!=f){
            siz[x] += siz[t];
            tmp = max(tmp, dfs(t, x, d+1, hx)+1);
        }
    }
    return tmp;
}
void work(int x){
    vis[x] = true;
    sf[1] = sg[1] = 1;
    int tmp=0;
    for(int i=hea[x]; i; i=edge[i].nxt){
        int t=edge[i].too;
        if(!vis[t]){
            int k=min(m, dfs(t, x, 2, ss[x])+1);
            tmp = max(tmp, k);
            for(int j=1; j<=k; j++){
                sf[j] += ff[j];
                sg[j] += gg[j];
                ff[j] = gg[j] = 0;
            }
        }
    }
    for(int i=1; i<=tmp; i++)
        sf[i] = sg[i] = 0;
    for(int i=hea[x]; i; i=edge[i].nxt){
        int t=edge[i].too;
        if(!vis[t]){
            rot = 0;
            tot = siz[t];
            getRoot(t, x);
            work(rot);
        }
    }
}
int main(){
    cin>>T;
    while(T--){
        rn(n); rn(m);
        scanf("%s", ss+1);
        memset(hea, 0, sizeof(int)*(n+1));
        memset(vis, 0, sizeof(bool)*(n+1));
        cnt = ans = rot = 0;
        tot = n;
        for(int i=1; i<n; i++){
            rn(uu); rn(vv);
            add_edge(uu, vv);
            add_edge(vv, uu);
        }
        scanf("%s", tt+1);
        bse[0] = 1;
        for(int i=1; i<=n; i++){
            bse[i] = bse[i-1] * 131;
            hs1[i] = hs1[i-1] + tt[(i-1)%m+1] * bse[i-1];
            hs2[i] = hs2[i-1] + tt[m-(i-1)%m] * bse[i-1];
        }
        rnd[0] = 0x3f3f3f3f;
        getRoot(1, 0);
        work(rot);
        printf("%llu\n", ans);
    }
    return 0;
}

转载于:https://www.cnblogs.com/poorpool/p/9044815.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值