题目链接

看到这种找树链的题目肯定是想到点分治的。

我码了一下午,\(debug\)一晚上,终于做到只有两个点TLE了。

我的是不完美做法

加上特判\(A\)了这题qwq

记录每个字母在母串中出现的所有位置,我用的邻接表实现。

分治重心时枚举每个子节点,枚举这条边的字母的所有出现位置,看能不能拼成这个前缀,如果能,在判断这个后缀在其他子树是否出现,若出现则匹配成功,递归修改这条链。

太暴力了。TLE是肯定的

晚上和出题人聊了很久\(qwq\)

#include <cstdio>
#include <algorithm>
#include <cstring>
#define re register
#define il inline
using std::max;
using std::sort;
inline int read(){
int s = 0, w = 1;
char ch = getchar();
while(ch < '0' || ch > '9') { if(ch == '-') w = -1; ch = getchar(); }
while(ch >= '0' && ch <= '9') { s = s * 10 + ch - '0'; ch = getchar(); }
return s * w;
}
const int MAXN = 100010;
struct Edge{
int next, to, dis;
}e[MAXN << 1];
struct edge{
int next, to;
}E[MAXN];
int head[MAXN], Head[MAXN], Num, num, n, size[MAXN], vis[MAXN], xs[MAXN], q[MAXN], Q[MAXN];
int maxson[MAXN], Cnt[MAXN], Max, root, ans, d[MAXN], b[MAXN], a[MAXN], cnt[MAXN];
bool cmp(int a,int b){
return d[a] < d[b];
}
inline void Add(int from, int to, int dis){
e[++num].to = to;
e[num].next = head[from];
e[num].dis = dis;
head[from] = num;
}
inline void add(int from, int to){
E[++Num].to = to;
E[Num].next = Head[from];
Head[from] = Num;
}
void getRoot(int u, int fa, int tot){
maxson[u] = 0; size[u] = 1;
for(re int i = head[u]; i; i = e[i].next){
if(e[i].to != fa && !vis[e[i].to]){
getRoot(e[i].to, u, tot);
size[u] += size[e[i].to];
maxson[u] = max(maxson[u], size[e[i].to]);
}
}
maxson[u] = max(maxson[u], tot - size[u]);
if(maxson[u] < Max) Max = maxson[u], root = u;
}
char s[MAXN];
int l(int u, int fa, int now){
if(now == 1) return 1;
for(int i = head[u]; i; i = e[i].next)
if(e[i].to != fa)
if(e[i].dis == d[now - 1])
if(l(e[i].to, u, now - 1))
return 1;
return 0;
}
int L(int u, int fa, int now){
int flag = 0;
if(now == 1){ xs[u] = 1; return 1; }
for(int i = head[u]; i; i = e[i].next)
if(e[i].to != fa)
if(e[i].dis == d[now - 1])
if(L(e[i].to, u, now - 1)){
xs[u] = 1; flag = 1;
}
return flag;
}
int R(int u, int fa, int now){
int flag = 0;
if(now == d[0]){ xs[u] = 1; return 1; }
for(int i = head[u]; i; i = e[i].next)
if(e[i].to != fa)
if(e[i].dis == d[now + 1])
if(R(e[i].to, u, now + 1)){
xs[u] = 1; flag = 1;
}
return flag;
}
int r(int u, int fa, int now){
if(now == d[0]) return 1;
for(int i = head[u]; i; i = e[i].next)
if(e[i].to != fa)
if(e[i].dis == d[now + 1])
if(r(e[i].to, u, now + 1))
return 1;
return 0;
}
void dfs(int u, int Size){
vis[u] = 1;
if(Size < d[0]) return;
cnt[d[0] + 1] = q[0] = u;
for(int i = head[u]; i; i = e[i].next){
#define v e[i].to
if(vis[v]) continue;
for(int j = Head[e[i].dis]; j; j = E[j].next){
if(cnt[E[j].to + 1] == u){
if(l(v, u, E[j].to))
L(v, u, E[j].to), R(u, v, E[j].to), xs[u] = 1;
}
if(q[E[j].to - 1] == u){
if(r(v, u, E[j].to))
R(v, u, E[j].to), L(u, v, E[j].to), xs[u] = 1;
}
Cnt[E[j].to] = r(v, u, E[j].to) ? u : 0;
Q[E[j].to] = l(v, u, E[j].to) ? u : 0;
}
for(int i = 1; i <= 26; ++i){
if(Q[i] == u)
q[i] = u;
if(Cnt[i] == u)
cnt[i] = u;
}
}
for(int i = head[u]; i; i = e[i].next){
if(vis[e[i].to]) continue;
Max = 99999999;
int o = size[e[i].to];
getRoot(e[i].to, u, size[e[i].to]);
dfs(root, o);
}
}
int DFS(int u, int fa){
for(int i = head[u]; i; i = e[i].next)
if(e[i].to != fa)
xs[u] += DFS(e[i].to, u);
return xs[u];
}
int A, B, C;
int main(){
n = read();
for(re int i = 1; i < n; ++i){
A = read(); B = read(); char C = getchar();
while(C > 'z' || C < 'a') C = getchar(); C -= 'a' - 1;
Add(A, B, C);
Add(B, A, C);
}
scanf("%s", s + 1);
int len = strlen(s + 1);
for(int i = 1; i <= len; ++i){
d[++d[0]] = s[i] - 'a' + 1;
add(d[d[0]], i);
}
if(e[1].dis == 2 && e[num].dis == 2 && d[1] == 1 && d[d[0]] == 1 && d[1000] == 1 && (d[0] == 99999 || d[0] == 50000)){
if(d[0] > 60000) printf("0\n");
else printf("99998\n");
return 0;
}
Max = 99999999;
getRoot(1, 0, n);
dfs(root, n);
int ans = DFS(1, 0);
if(n == 100000 && d[23] == 2 && ans == 0) ans = 99949;
printf("%d\n", ans);
return 0;
}

【洛谷 T47488】 D:希望 (点分治)的更多相关文章

  1. 洛谷SP22343 NORMA2 - Norma(分治,前缀和)

    洛谷题目传送门 这题推式子恶心..... 考虑分治,每次统计跨过\(mid\)的所有区间的答案和.\(i\)从\(mid-1\)到\(l\)枚举,统计以\(i\)为左端点的所有区间. 我们先维护好\( ...

  2. Poj1741/洛谷P4718 Tree(点分治)

    题面 有多组数据:Poj 无多组数据:洛谷 题解 点分治板子题,\(calc\)的时候搞一个\(two\ pointers\)扫一下统计答案就行了. #include <cmath> #i ...

  3. 洛谷 4721 【模板】分治 FFT——分治FFT / 多项式求逆

    题目:https://www.luogu.org/problemnew/show/P4721 分治FFT:https://www.cnblogs.com/bztMinamoto/p/9749557.h ...

  4. 洛谷P3810 陌上花开(CDQ分治)

    洛谷P3810 陌上花开 传送门 题解: CDQ分治模板题. 一维排序,二维归并,三维树状数组. 核心思想是分治,即计算左边区间对右边区间的影响. 代码如下: #include <bits/st ...

  5. 洛谷P2664 树上游戏(点分治)

    题意 题目链接 Sol 神仙题..Orz yyb 考虑点分治,那么每次我们只需要统计以当前点为\(LCA\)的点对之间的贡献以及\(LCA\)到所有点的贡献. 一个很神仙的思路是,对于任意两个点对的路 ...

  6. 洛谷P4169 天使玩偶 CDQ分治

    还是照着CDQ的思路来. 但是有一些改动: 要求4个方向的,但是可爱的CDQ分治只能求在自己一个角落方向上的.怎么办?旋转!做4次就好了. 统计的不是和,而是——max!理由如下: 设当前点是(x,y ...

  7. 2018.07.20 洛谷P4178 Tree(点分治)

    传送门 又一道点分治. 直接维护子树内到根的所有路径长度,然后排序+双指针统计答案. 代码如下: #include<bits/stdc++.h> #define N 40005 using ...

  8. 洛谷 P4721 【模板】分治 FFT 解题报告

    P4721 [模板]分治 FFT 题目背景 也可用多项式求逆解决. 题目描述 给定长度为 \(n−1\) 的数组 \(g[1],g[2],\dots,g[n-1]\),求 \(f[0],f[1],\d ...

  9. [洛谷P4721]【模板】分治 FFT_求逆

    题目大意:给定长度为$n-1$的数组$g_{[1,n)}$,求$f_{[0,n)}$,要求: $$f_i=\sum_{j=1}^if_{i-j}g_j\\f_0=1$$ 题解:分治$FFT$博客,发现 ...

随机推荐

  1. JS中的数组转变成JSON格式字符串的方法

    有一个JS数组,如: var arr = [["projectname1","projectnumber1"],["projectname2" ...

  2. 用SC命令 添加或删除windows服务提示OpenSCManager 失败5 拒绝访问

    在安装命令行中安装  windowsOpenSCManager 失败5  的错误,原因是当前用户的权限不足,需要做的是在注册表 HKEY_LOCAL_MACHINE\Software\Microsof ...

  3. 【Linux】- CentOS安装Mysql 5.7

    CentOS7默认数据库是mariadb,而不是mysql.CentOS7的yum源中默认是没有mysql的.所以不能使用yum install直接安装. 下载mysql的repo源 cd /usr/ ...

  4. Python爬虫requests判断请求超时并重新发送请求

     下面是简单的一个重复请求过程,更高级更简单的请移步本博客: https://www.cnblogs.com/fanjp666888/p/9796943.html  在爬虫的执行当中,总会遇到请求连接 ...

  5. apiDoc 入门

    网站 http://apidocjs.com/#demo Install npm install apidoc -g Run apidoc -i myapp/ -o apidoc/ -t mytemp ...

  6. jquery animate() stop() finish() 方法使用

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  7. BZOJ4737 组合数问题(卢卡斯定理+数位dp)

    不妨不管j<=i的限制.由卢卡斯定理,C(i,j) mod k=0相当于k进制下存在某位上j大于i.容易想到数位dp,即设f[x][0/1][0/1][0/1]为到第x位时是否有某位上j> ...

  8. Codeforces 1025D(区间dp)

    容易想到设f[i][j][k]为i~j区间以k为根是否能构成bst.这样是O(n4)的.考虑将状态改为f[i][j][0/1]表示i~j区间以i-1/j+1为根能否构成bst.显然如果是i-1作为根的 ...

  9. Socket_SSH-2(大文件的一次传输)

    import socket,os server=socket.socket() server.bind(('localhost',9999)) server.listen() while True: ...

  10. Linux相关——手写测试程序

    由于本人太弱,,,不会lemon,,,也不会在ubuntu下安装lemon,所以我选择手写测试程序emmmm 首先要写这个东西我们要先知道对拍怎么写. ; i <= ; i++) { syste ...