hdu4812 D Tree,平衡树,启发式合并
2014-10-05 00:48
176 查看
今天模拟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; }
相关文章推荐
- [BZOJ2733][HNOI2012]永无乡(平衡树+启发式合并)
- poj1741 Tree,平衡树,启发式合并
- BZOJ 2733 HNOI 2012 永无乡 平衡树启发式合并
- [平衡树+启发式合并 || 点分治] POJ1741 Tree
- bzoj 2733 平衡树启发式合并
- [APIO2012]派遣 (平衡树启发式合并)
- 【pb_ds】【平衡树启发式合并】【并查集】bzoj2733 [HNOI2012]永无乡
- SPOJ FTOUR2 (平衡树+启发式合并/点分治)
- [BZOJ3545][ONTAK2010][平衡树][STL][启发式合并]Peaks
- BZOJ 1483: [HNOI2009]梦幻布丁 链表或者平衡树启发式合并
- [平衡树 启发式合并] BZOJ 1483 [HNOI2009]梦幻布丁
- [BZOJ][平衡树+启发式合并][替罪羊树]2733: [HNOI2012]永无乡
- 【BZOJ2212】Tree Rotations(POI2011)-平衡树启发式合并
- BZOJ 2809 APIO 2012 dispatching 平衡树启发式合并
- [BZOJ2733][HNOI2012][启发式合并][平衡树]永无乡
- 【平衡树启发式合并】POJ1741[Tree]题解
- hdu 4670 Cube number on a tree,平衡树,启发式合并
- ☆ [HNOI2012] 永无乡 「平衡树启发式合并」
- BZOJ2733 [HNOI2012]永无乡 平衡树启发式合并
- BZOJ 2809: [Apio2012]dispatching( 平衡树 + 启发式合并 )