HDU5469 Antonidas(树分治&&哈希)
给你一颗点上有字符的树,问一个给定的字符串是否是这棵树上的两点的路径。
树分治的思想就是每次找重心,重心下的子问题分解去做,然后就是合并了。合并的时候用一个总的set<pair<len,hash>> 去存从根节点往下走的长度以及对应的hash值,判的时候只需要看下是否已经存在 m-len,以及对应的前缀(或者后缀)的哈希值,然后再加进来。
两个优化的点是,1是递归解子问题的时候如果子树规模小于要给的字符串可以不用递归下去。2是存pair的时候只需要存前缀的pair以及后缀的pair,其它的都不用存。
加了这些优化之后我的程度勉强能在4000ms内通过。看来我树分治的写法还是太慢了。。
#pragma warning(disable:4996)
#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <cmath>
#include <algorithm>
#include <string>
#include <cstdlib>
#include <ctime>
#include <map>
#include <set>
using namespace std; #define maxn 10010
#define ll long long
#define MP make_pair vector<int> G[maxn];
bool centroid[maxn];
int ssize[maxn];
char val[maxn];
char tar[maxn];
set<pair<ll, ll> > sta;
set<pair<ll, ll> >::iterator it;
int n, m; ll mod_num;
ll mod;
ll xpow[maxn];
ll pre[maxn];
ll post[maxn]; ll xorr(ll x, ll y)
{
return (x*mod_num%mod + y) % mod;
} int compute_ssize(int v, int p)
{
int c = 1;
for (int i = 0; i<G[v].size(); ++i){
int w = G[v][i];
if (w == p || centroid[w]) continue;
c += compute_ssize(G[v][i], v);
}
ssize[v] = c;
return c;
} pair<int, int> search_centroid(int v, int p, int t)
{
pair<int, int> res = make_pair(INT_MAX, -1);
int s = 1, m = 0;
for (int i = 0; i < G[v].size(); ++i){
int w = G[v][i];
if (w == p || centroid[w]) continue;
res = min(res, search_centroid(w, v, t));
m = max(m, ssize[w]);
s += ssize[w];
}
m = max(m, t - s);
res = min(res, make_pair(m, v));
return res;
} void enumerate_mul(int v, int p, pair<ll, ll> d, set<pair<ll, ll> > &ds)
{
if (!ds.count(d)) ds.insert(d);
for (int i = 0; i < G[v].size(); ++i){
int w = G[v][i];
if (w == p || centroid[w]) continue;
enumerate_mul(w, v, MP(d.first + 1, xorr(d.second, val[w])), ds);
}
} bool judge(pair<ll, ll> x, const set<pair<ll, ll> >& tds)
{
if (pre[x.first] == x.second){
return tds.count(MP(m - x.first, post[x.first + 1]));
}
if (post[m - x.first + 1] == x.second){
return tds.count(MP(m - x.first, pre[m - x.first]));
}
return false;
} bool solve(int v)
{
compute_ssize(v, -1);
int s = search_centroid(v, -1, ssize[v]).second;
centroid[s] = true;
for (int i = 0; i<G[s].size(); ++i){
if (centroid[G[s][i]]) continue;
if (ssize[G[s][i]] < m){
continue;
}
if (solve(G[s][i])) {
return true;
}
}
sta.clear();
sta.insert(MP(1, val[s]));
if (m == 1 && val[s] == tar[1]){
return true;
}
set<pair<ll, ll> > tds;
for (int i = 0; i<G[s].size(); ++i){
if (centroid[G[s][i]]) continue;
tds.clear();
enumerate_mul(G[s][i], s, MP(1, val[G[s][i]]), tds);
it = tds.begin();
while (it != tds.end()){
if (judge(*it, sta)){
return true;
}
++it;
}
it = tds.begin();
while (it != tds.end()){
ll one = (*it).first;
ll two = (*it).second;
pair<ll, ll> vv;
if (one > m){
++it; continue;
}
if (pre[one] != two && post[m - one + 1] != two){
++it;
continue;
}
if (tar[one + 1] != val[s] && tar[m - one] != val[s]){
++it;
continue;
}
vv.first = one + 1;
vv.second = (xpow[one] * val[s] % mod + two) % mod;
if (!sta.count(vv)){
sta.insert(vv);
}
++it;
}
}
centroid[s] = false;
return false;
} ll haha[3] = { 37, 23, 53 };
ll tata[2] = { 1000000007, 1000010009 }; int main()
{
int T; cin >> T; int ca = 0;
while (T--)
{
cin >> n;
for (int i = 0; i <= n; ++i) G[i].clear();
int ui, vi;
for (int i = 0; i < n - 1; ++i){
scanf("%d%d", &ui, &vi);
G[ui].push_back(vi);
G[vi].push_back(ui);
}
memset(centroid, 0, sizeof(centroid));
scanf("%s", val + 1);
scanf("%s", tar + 1);
mod_num = haha[rand() % 3];
mod = tata[rand() % 2];
xpow[0] = 1;
for (int i = 1; i <= n; ++i){
xpow[i] = xpow[i - 1] * mod_num%mod;
}
pre[0] = 0;
m = strlen(tar + 1);
for (int i = 1; i <= m; ++i){
pre[i] = (xpow[i - 1] * tar[i] % mod + pre[i - 1]) % mod;
}
post[m + 1] = 0;
for (int i = m; i >= 1; --i){
post[i] = (tar[i] * xpow[m - i] % mod + post[i + 1]) % mod;
}
bool flag = solve(1);
if (flag){
printf("Case #%d: Find\n", ++ca);
}
else{
printf("Case #%d: Impossible\n", ++ca);
}
}
return 0;
}
HDU5469 Antonidas(树分治&&哈希)的更多相关文章
- hdu4812 逆元+树分治
逆元链接:https://www.cnblogs.com/zzqc/p/7192436.html 经典的树分治题 #pragma comment("linker,"/STACK:1 ...
- hdu-5977 Garden of Eden(树分治)
题目链接: Garden of Eden Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/ ...
- 【BZOJ-1468】Tree 树分治
1468: Tree Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 1025 Solved: 534[Submit][Status][Discuss] ...
- HDU 4812 D Tree 树分治+逆元处理
D Tree Problem Description There is a skyscraping tree standing on the playground of Nanjing Unive ...
- BZOJ 2152: 聪聪可可 树分治
2152: 聪聪可可 Description 聪聪和可可是兄弟俩,他们俩经常为了一些琐事打起来,例如家中只剩下最后一根冰棍而两人都想吃.两个人都想玩儿电脑(可是他们家只有一台电脑)……遇到这种问题,一 ...
- POJ 1741 Tree 树分治
Tree Description Give a tree with n vertices,each edge has a length(positive integer less than 1 ...
- UVALive 7148 LRIP【树分治+线段树】
题意就是要求一棵树上的最长不下降序列,同时不下降序列的最小值与最大值不超过D. 做法是树分治+线段树,假设树根是x,y是其当前需要处理的子树,对于子树y,需要处理出两个数组MN,MX,MN[i]表示以 ...
- BZOJ 2566 xmastree(树分治+multiset)
题目链接:http://www.lydsy.com:808/JudgeOnline/problem.php?id=2566 题意:一棵有边权的树.结点有颜色.每次修改一个点的颜色.求每次修改后所有同色 ...
- 树分治&树链剖分相关题目讨论
预备知识 树分治,树链剖分 poj1741 •一棵有n个节点的树,节点之间的边有长度.方方方想知道,有多少个点对距离不超过m 题解 点分治模板题.详见我早上写的http://www.cnblogs ...
随机推荐
- Android toolbar menu 字体点击样式
今天在做toolbar的时候,右边的菜单的点击事件,就是文字,然后文字的样式,文字的大小,文字的颜色,高了半天.最后发现,文字点下去之后是有样式的,也就是按下去有阴影. 哥哥的耐心好,就知道这不是问题 ...
- URL地址传参中特殊符号的转码和解码
背景: URL传参在web开发中很常见,一般来说这种方式并不推荐,原因就是浏览器多种多样,各家浏览器对URL地址的解析的表现很不一样,特别是当参数有非ASCII字符.英文字母.阿拉伯数字时. 在CRM ...
- Eclipse 修改字符集---Eclipse教程第02课
默认情况下 Eclipse 字符集为 GBK,但现在很多项目采用的是 UTF-8,这是我们就需要设置我们的 Eclipse 开发环境字符集为 UTF-8, 设置步骤如下: 在菜单栏选择 Window ...
- 无限小数转分数POJ1930分析
将无限小数化为分数,有一套简单的公式.使其轻松表示出来. 循环节 例如:0.121212…… 循循环节为12. 公式 这个公式必须将循环节的开头放在十分位.若不是可将原数乘10^x(x为正整数) ...
- 解决 ld: library not found for -lPods的问题
现在打开有pods建好的workspace文件,尝试编译,会报ld: library not found for -lPods错误,原因就是工程里面的设置项覆盖了pods中xcconfig中的设置.解 ...
- Vbs 测试程序二
这是一段原载于百度百科上的代码,Chaobs转载 原帖已删,就是怕有人用这个恶意程序. 慎用! dim folder,fso,foldername,f,d,dc set fso=createobjec ...
- 一个关于pynoi游戏的C语言编程
"去吧,秦,好好享受这个夜晚,我给你准备了一份礼物,希望你能喜欢."小布莱克眨着眼睛笑道,狡猾的像一头小狐狸.
- pythondifflib模块讲解示例
版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/Lockey23/article/details/77913855 difflib模块提供的类和方法用 ...
- springboot整合jersey
https://blog.csdn.net/xiongpei00/article/details/76576420
- vue零碎收集
在组件中创建dom: let a=document.querySelector('.test'); let newDom=document.createElement("div") ...