今天模拟2013南京赛,两个半小时做完5题开始梦游。
每次都出不了难题有木有!都是水题的场手速又拼不过有木有!
hdu4812 D Tree,南京的k题。
每个点有一个权值,问是否存在一条路径,路径所有点的权值乘积模1e6+3等于k。
这个题,大家基本都是用点分治过的,复杂度O(nlogn)。
这里介绍一个有趣的解法,也是一个我感觉很有用的思想:启发式合并。
先说说启发式合并。
启发式合并就是对于两个相同的数据结构,将点数小的数据结构的点一个个暴力插入点大的数据结构中。
如此就完成了这两个数据结构的合并。
再来说说这玩意神奇之处。
以平衡树为例,一开始有n个点,每个点有包含本身的点的平衡树。
然后将任意两点的平衡树合并,最后合并成一棵树。
如果每次都遵循小的插到大的这样的合并方式,可以证明,插入的次数不会超过O(nlogn)次。
这里简单证明一下:对于每个点,如果它从小的树拔出来插到了大的树上,那么它所在的树的大小至少会增加一倍。
树最大就是n个点,那么这个点最大的插入次数不会超过 logn 次。
这样,本题就可以用这种方式求解了。
每个叶子节点,建一个包含自己的平衡树。
非叶子节点,从子节点中选一个点数最大的,将它的平衡树作为自己的平衡树,再将其它子节点的平衡树合并到这个平衡树中。
合并的过程查找是否有匹配的值并更新答案。复杂度O(nlognlogn)。
自己生成了一些随机大数据,比点分治要稍慢一些,但是在hdu提交居然要比某些点分治更快,2000+ms。
数的逆元要在开始时预处理,不然会悲剧。
具体看代码吧:
每次都出不了难题有木有!都是水题的场手速又拼不过有木有!
hdu4812 D Tree,南京的k题。
每个点有一个权值,问是否存在一条路径,路径所有点的权值乘积模1e6+3等于k。
这个题,大家基本都是用点分治过的,复杂度O(nlogn)。
这里介绍一个有趣的解法,也是一个我感觉很有用的思想:启发式合并。
先说说启发式合并。
启发式合并就是对于两个相同的数据结构,将点数小的数据结构的点一个个暴力插入点大的数据结构中。
如此就完成了这两个数据结构的合并。
再来说说这玩意神奇之处。
以平衡树为例,一开始有n个点,每个点有包含本身的点的平衡树。
然后将任意两点的平衡树合并,最后合并成一棵树。
如果每次都遵循小的插到大的这样的合并方式,可以证明,插入的次数不会超过O(nlogn)次。
这里简单证明一下:对于每个点,如果它从小的树拔出来插到了大的树上,那么它所在的树的大小至少会增加一倍。
树最大就是n个点,那么这个点最大的插入次数不会超过 logn 次。
这样,本题就可以用这种方式求解了。
每个叶子节点,建一个包含自己的平衡树。
非叶子节点,从子节点中选一个点数最大的,将它的平衡树作为自己的平衡树,再将其它子节点的平衡树合并到这个平衡树中。
合并的过程查找是否有匹配的值并更新答案。复杂度O(nlognlogn)。
自己生成了一些随机大数据,比点分治要稍慢一些,但是在hdu提交居然要比某些点分治更快,2000+ms。
数的逆元要在开始时预处理,不然会悲剧。
具体看代码吧:
#pragma comment(linker,"/STACK:102400000,102400000")
#include<iostream>
#include<cstdio>
#include<cstring>
#include<map>
using namespace std;
#define NN 101000
#define MM 1001000
map<int,int> mp[NN];
int k,n;
int te,fi[NN],ne[NN*2],v[NN*2];
int ans1,ans2,tm;
int pinv[MM];
int son[NN],tot[NN],mul[NN];
int val[NN];
int tr[NN];
const int inf = 101000000;
const int mod = 1000003;
void extend_gcd(int a,int b,int &x,int &y){
if (b==0){
x=1,y=0;return;
}
else{
extend_gcd(b,a%b,x,y);
int t=x;
x=y;
y=t-a/b*y;
return;
}
}
void init_inv(){
int i;
int x,y;
pinv[0]=0;
int tmod=mod;
for(i=1;i<mod;++i){
extend_gcd(i,tmod,x,y);
x=(x%mod+mod)%mod;
pinv[i]=x;
}
}
void addedge(int a,int b){
ne[te]=fi[a];fi[a]=te;v[te]=b;
te++;
}
void dfs(int u,int fa){
int e,vv,ma=-1;
son[u]=-1;
tot[u]=1;
for(e=fi[u];e!=-1;e=ne[e]){
vv=v[e];
if (vv!=fa){
dfs(vv,u);
tot[u]+=tot[vv];
if (tot[vv]>ma) {ma=tot[vv];son[u]=vv;}
}
}
}
void dfs2(int u,int fa){
int e,vv;
int tmp,tinv,a,b;
if (son[u]==-1){
tr[u]=++tm;mp[tm][1]=u;mul[u]=val[u];
return;
}
else {
dfs2(son[u],u);tr[u]=tr[son[u]];
mul[u]=mul[son[u]];
tinv=(long long)mul[u]*val[u]%mod;
tinv=(long long)pinv[tinv]*k%mod;
if (mp[tr[u]].find(tinv)!=mp[tr[u]].end()){
a=mp[tr[u]][tinv];
b=u;
if (a>b) {int tt=a;a=b;b=tt;}
if (a<ans1||(a==ans1&&b<ans2)) {ans1=a;ans2=b;}
}
vv=pinv[mul[u]];
if ((mp[tr[u]].find(vv)!=mp[tr[u]].end()&&mp[tr[u]][vv]>u)||(mp[tr[u]].find(vv)==mp[tr[u]].end())){
mp[tr[u]][vv]=u;
}
}
for(e=fi[u];e!=-1;e=ne[e]){
vv=v[e];
if (vv!=fa&&vv!=son[u]){
dfs2(vv,u);
map<int,int>::iterator it;
for(it=mp[tr[vv]].begin();it!=mp[tr[vv]].end();it++){
tmp=(long long)it->first;
tmp=(long long)tmp*mul[vv]%mod;
tinv=(long long)tmp*mul[u]%mod*val[u]%mod;
tinv=(long long)pinv[tinv]*k%mod;
if (mp[tr[u]].find(tinv)!=mp[tr[u]].end()){
a=mp[tr[u]][tinv];
b=it->second;
if (a>b) {int tt=a;a=b;b=tt;}
if (a<ans1||(a==ans1&&b<ans2)) {ans1=a;ans2=b;}
}
tmp=(long long)tmp*pinv[mul[u]]%mod;
if ((mp[tr[u]].find(tmp)!=mp[tr[u]].end()&&mp[tr[u]][tmp]>it->second)||(mp[tr[u]].find(tmp)==mp[tr[u]].end())){
mp[tr[u]][tmp]=it->second;
}
}
}
}
mul[u]=(long long)mul[u]*val[u]%mod;
}
int main(){
//freopen("kin2.txt","r",stdin);
int i,a,b;
init_inv();
while(scanf("%d%d",&n,&k)!=EOF){
for(i=1;i<=n;++i){
scanf("%d",&val[i]);
mp[i].clear();
}
te=0;
memset(fi,-1,sizeof(fi));
for(i=1;i<n;++i){
scanf("%d%d",&a,&b);
addedge(a,b);
addedge(b,a);
}
ans1=inf;ans2=inf;
dfs(1,-1);
tm=0;
dfs2(1,-1);
if (ans1==inf){printf("No solution\n");}
else printf("%d %d\n",ans1,ans2);
}
return 0;
}