HDU5469 樹分治、hash
阿新 • • 發佈:2019-01-24
題意:問能否在樹上找到一條路徑使得路徑經過的點的單詞可以組成提問的串~~
樹分治 肯定還有hash~~~
sb的想法就不說了~~~
這裡開一個int in_pre[]、in_suf來記錄是這個字首以及這個字尾是否出現了 int型用來當時間戳~~
直接進行點分治、然後對於當前點的子樹要進行DFS、4次
第一次找出當前子樹(不包括根)、串的字尾,看看之前的子樹沒有字首進行匹配
第二次找出當前子樹(包括根)、串的字首,看看之前的子樹有沒有後綴進行匹配
第三第四次進行更新資訊~~
#include <algorithm> #include <iostream> #include<string.h> #include <fstream> #include <math.h> #include <vector> #include <cstdio> #include <string> #include <queue> #include <stack> #include <map> #include <set> #define exp 1e-8 #define fi first #define se second #define ull unsigned long long #define INF 0x3f3f3f3f #define pb(a) push_back(a) #define mp(a,b) make_pair(a,b) #define all(a) a.begin(),a.end() #define mm(a,b) memset(a,b,sizeof(a)); #define for0(a,b) for(int a=0;a<=b;a++)//0---(b-1) #define for1(a,b) for(int a=1;a<=b;a++)//1---(b) #define rep(a,b,c) for(int a=b;a<=c;a++)//b---c #define repp(a,b,c)for(int a=b;a>=c;a--)/// #define cnt_one(i) __builtin_popcount(i) #define stl(c,itr) for(__typeof((c).begin()) itr=(c).begin();itr!=(c).end();itr++) using namespace std; void bug(string m="here"){cout<<m<<endl;} template<typename __ll> inline void READ(__ll &m){__ll x=0,f=1;char ch=getchar();while(!(ch>='0'&&ch<='9')){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}m=x*f;} template<typename __ll>inline void read(__ll &m){READ(m);} template<typename __ll>inline void read(__ll &m,__ll &a){READ(m);READ(a);} template<typename __ll>inline void read(__ll &m,__ll &a,__ll &b){READ(m);READ(a);READ(b);} template<typename __ll>inline void read(__ll &m,__ll &a,__ll &b,__ll &c){READ(m);READ(a);READ(b);READ(c);} template<typename __ll>inline void read(__ll &m,__ll &a,__ll &b,__ll &c,__ll &d){READ(m);READ(a);READ(b);READ(c);read(d);} template < class T > inline void out(T a){if(a>9)out(a/10);putchar(a%10+'0');} template < class T > inline void outln(T a){if(a>9)out(a/10);putchar(a%10+'0');puts("");} template < class T > inline void out(T a,T b){out(a);putchar(' ');out(b);} template < class T > inline void outln(T a,T b){out(a);putchar(' ');outln(b);} template < class T > inline void out(T a,T b,T c){out(a);putchar(' ');out(b);putchar(' ');out(c);} template < class T > inline void outln(T a,T b,T c){out(a);putchar(' ');outln(b);putchar(' ');outln(b);} template < class T > T gcd(T a, T b) { return b ? gcd(b, a % b) : a; } template < class T > T lcm(T a, T b) { return a / gcd(a, b) * b; } template < class T > inline void rmin(T &a, const T &b) { if(a > b) a = b; } template < class T > inline void rmax(T &a, const T &b) { if(a < b) a = b; } template < class T > T pow(T a, T b) { T r = 1; while(b > 0) { if(b & 1) r = r * a; a = a * a; b /= 2; } return r; } template < class T > T pow(T a, T b, T mod) { T r = 1; while(b > 0) { if(b & 1) r = r * a % mod; a = a * a % mod; b /= 2; } return r; } const int mod=0x7FFFFFFF; const int maxn=10010; ull pre[maxn],suf[maxn],f[maxn]; const ull seed=31; int in_pre[maxn],in_suf[maxn],idx; bool flag; const int cnt_edge=maxn*2; //修改啊 const int cnt_v=maxn; int head[cnt_v],cnt_e; struct EDGE{int u,v,next,cost;}edge[cnt_edge]; void init(){cnt_e=0;memset(head,-1,sizeof(head));} void addedge(int u,int v,int cost=0) {edge[cnt_e].u=u;edge[cnt_e].v=v;edge[cnt_e].cost=cost;edge[cnt_e].next=head[u];head[u]=cnt_e++;} int n,k; int root,tot; int minn,size[maxn];///minn:衡量某個節點是否能當重心,minn越小 就越可以當重心、size[i] i子樹的大小 bool del[maxn];///記錄是否已經刪除這個點... char ch[maxn],s[maxn]; void getroot(int u,int fa) { size[u]=1; int maxn=0; for(int i=head[u];i!=-1;i=edge[i].next) { int v=edge[i].v; if(v==fa||del[v])continue;///這裡必須要加上del[v] getroot(v,u); size[u]+=size[v]; maxn=max(maxn,size[v]); } maxn=max(maxn,tot-size[u]); if(maxn<minn)root=u,minn=maxn; } void dfs1(int u,int fa,ull len,int deep,int op)///找字尾~~不包含頭~~ { len%=mod; if(flag||deep>=k)return; if(suf[deep]==len&&in_pre[k-deep]==idx&&op==0) { flag=1; return; } if(suf[deep]==len&&op==1) in_suf[deep]=idx; for(int i=head[u];i!=-1;i=edge[i].next) { int v=edge[i].v; if(v==fa||del[v])continue; dfs1(v,u,(len+(ch[v]-'a'+1)*f[deep])&mod,deep+1,op); } } void dfs2(int u,int fa,ull len,int deep,int op)///找字首、包括根~~ { if(flag||deep>k)return; if(pre[deep]==len&&in_suf[k-deep]==idx&&op==0) { flag=1; return; } if(pre[deep]==len&&op==1) in_pre[deep]=idx; for(int i=head[u];i!=-1;i=edge[i].next) { int v=edge[i].v; if(v==fa||del[v])continue; dfs2(v,u,(len+(ch[v]-'a'+1)*f[deep])&mod,deep+1,op); } } void word(int u) { del[u]=1; in_suf[0]=in_pre[0]=++idx; if(ch[u]-'a'+1==pre[1])in_pre[1]=idx;///預處理出這個root單獨做字首~~ for(int i=head[u];i!=-1;i=edge[i].next) { int v=edge[i].v; if(del[v])continue; dfs1(v,u,ch[v]-'a'+1,1,0);///尋找字尾~~ if(flag){return;} dfs2(v,u,(ch[v]-'a'+1)*31+(ch[u]-'a'+1),2,0);///尋找字首~~ if(flag){return;} dfs1(v,u,ch[v]-'a'+1,1,1);///尋找字尾~~ dfs2(v,u,(ch[v]-'a'+1)*31+(ch[u]-'a'+1),2,1);///尋找字首~~ } for(int i=head[u];i!=-1;i=edge[i].next) { int v=edge[i].v; if(del[v])continue; minn=INF,tot=size[v]; getroot(v,u); word(root); } } int main() { f[0]=1; for1(i,10000)f[i]=f[i-1]*seed&mod; int cas; read(cas); for1(tt,cas) { init(); read(n); for1(i,n-1) { int a,b; read(a,b); addedge(a,b); addedge(b,a); } scanf("%s%s",ch+1,s); k=strlen(s);pre[0]=suf[0]=0; for(int i=0;i<k;i++) pre[i+1]=(pre[i]*31+s[i]-'a'+1)&mod; reverse(s,s+k); for(int i=0;i<k;i++) suf[i+1]=(suf[i]*31+s[i]-'a'+1)&mod; printf("Case #%d: ",tt); if(k==1) { for1(i,n)if(ch[i]==s[0])flag=1; if(flag==1) puts("Find"); else puts("Impossible"); continue; } idx=flag=0; memset(in_pre,0,sizeof in_pre); memset(in_suf,0,sizeof in_suf); memset(del,0,sizeof del); minn=INF,tot=n; getroot(1,0); word(root); if(flag==1) puts("Find"); else puts("Impossible"); } }