题意:问有多少条路径,符合路径上所有节点的权值乘积模1000003等于k。

解题关键:预处理阶乘逆元,然后通过hash和树形dp$O(1)$的判定乘积存在问题,注意此道题是如何处理路径保证不重复的,具有启发意义。

代码:2340ms,这段代码最重要的可取点就是如何通过操作省去memset的过程

复杂度:$O(n\log n)$

 #pragma comment(linker,"/STACK:102400000,102400000")
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<iostream>
#include<cmath>
#define maxn 100040
#define maxm 1000500
using namespace std;
typedef long long ll;
const ll mod=;
const ll inf=1ll<<;
ll n,k,ans,size,s[maxn],f[maxn],path[maxn],cr,val[maxn],inv[maxm],ansl,ansr;
ll head[maxn],cnt,root,pathid[maxn],flag[maxm],mp[maxm],ca;
bool vis[maxn];
struct edge{
ll to,nxt;
}e[maxn<<]; void add_edge(ll u,ll v){
e[cnt].to=v;
e[cnt].nxt=head[u];
head[u]=cnt++;
} inline ll read(){
char k=;char ls;ls=getchar();for(;ls<''||ls>'';k=ls,ls=getchar());
ll x=;for(;ls>=''&&ls<='';ls=getchar())x=(x<<)+(x<<)+ls-'';
if(k=='-')x=-x;return x;
} void get_root(ll u,ll fa){//get_root会用到size
s[u]=;f[u]=;//f是dp数组
for(ll i=head[u];i!=-;i=e[i].nxt){
ll v=e[i].to;
if(v==fa||vis[v]) continue;
get_root(v,u);
s[u]+=s[v];
f[u]=max(f[u],s[v]);
}
f[u]=max(f[u],size-s[u]);
root=f[root]>f[u]?u:root;
} void get_path_size(ll u,ll fa,ll dis){//同时获取size和depth,size是深度,depth是dis的意思
path[cr]=dis%mod*val[u]%mod;
pathid[cr]=u;
cr++;
s[u]=;
ll tm=path[cr-]%mod;
for(ll i=head[u];i!=-;i=e[i].nxt){
ll v=e[i].to;
if(v==fa||vis[v]) continue;
get_path_size(v,u,tm);
s[u]+=s[v];
}
} void getans(ll a,ll b){
if(a>b) swap(a,b);
if(ansl>a) ansl=a,ansr=b;
else if(ansl==a&&ansr>b) ansr=b;
} void work(ll u,ll fa){
vis[u]=true;
for(ll i=head[u];i!=-;i=e[i].nxt){
ll v=e[i].to;
if(v==fa||vis[v]) continue;
cr=;
get_path_size(v,u,);
for(ll j=;j<cr;j++){
if(path[j]*val[u]%mod==k) getans(pathid[j],u);
ll tm=k*inv[path[j]*val[u]%mod]%mod;
if(flag[tm]!=ca) continue;
getans(mp[tm],pathid[j]);
}
for(int j=;j<cr;j++){
ll tm=path[j];
if(flag[tm]!=ca||mp[tm]>pathid[j]) flag[tm]=ca,mp[tm]=pathid[j];
}
}
ca++;
for(ll i=head[u];i!=-;i=e[i].nxt){
ll v=e[i].to;
if(vis[v]||v==fa) continue;
size=s[v],root=;
get_root(v,u);
work(root,u);
}
// vis[u]=false;
} void init(){
memset(vis,,sizeof vis);
memset(head,-,sizeof head);
//memset(flag,0,sizeof flag);
ans=cnt=;
//ca=1;
} ll mod_pow(ll x,ll n,ll p){
ll res=;
while(n){
if(n&) res=res*x%p;
x=x*x%p;
n>>=;
}
return res;
} int main(){
ll a,b;
f[]=inf;inv[]=;
for(ll i=;i<;i++) inv[i]=mod_pow(i,mod-,mod);
ca=;
while(scanf("%lld%lld",&n,&k)!=EOF){
ca++;
init();
for(int i=;i<=n;i++) val[i]=read()%mod;
for(int i=;i<n-;i++){
a=read(),b=read();
add_edge(a,b);
add_edge(b,a);
}
size=n,root=;
get_root(,-);
ansl=ansr=inf;
work(root,-);
if(ansl==inf) printf("No solution\n");
else printf("%lld %lld\n",ansl,ansr);
}
return ;
}

[hdu4812]D Tree(点分治)的更多相关文章

  1. HDU4812 D Tree(树的点分治)

    题目大概说给一棵有点权的树,输出字典序最小的点对,使这两点间路径上点权的乘积模1000003的结果为k. 树的点分治搞了.因为是点权过根的两条路径的LCA会被重复统计,而注意到1000003是质数,所 ...

  2. HDU4812 D tree 【点分治 + 乘法逆元】

    D树 时间限制:10000/5000 MS(Java / Others)内存限制:102400/102400 K(Java / Others) 总共提交5400个已接受的提交1144 问题描述 南京理 ...

  3. 【点分治】【乘法逆元】hdu4812 D Tree

    思路比较裸,但是要把答案存到哈希表里面,这里需要一定技巧,否则会被K=1且点权全是1的数据卡飞.预处理乘法逆元.TLE了一天.换了种点分治的姿势…… #pragma comment(linker,&q ...

  4. 【BZOJ-1468】Tree 树分治

    1468: Tree Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 1025  Solved: 534[Submit][Status][Discuss] ...

  5. HDU 4812 D Tree 树分治+逆元处理

    D Tree Problem Description   There is a skyscraping tree standing on the playground of Nanjing Unive ...

  6. POJ 1741 Tree 树分治

    Tree     Description Give a tree with n vertices,each edge has a length(positive integer less than 1 ...

  7. [bzoj 1468][poj 1741]Tree [点分治]

    Description Give a tree with n vertices,each edge has a length(positive integer less than 1001). Def ...

  8. 【CF434E】Furukawa Nagisa's Tree 点分治

    [CF434E]Furukawa Nagisa's Tree 题意:一棵n个点的树,点有点权.定义$G(a,b)$表示:我们将树上从a走到b经过的点都拿出来,设这些点的点权分别为$z_0,z_1... ...

  9. POJ 1741 Tree(点分治点对<=k)

    Description Give a tree with n vertices,each edge has a length(positive integer less than 1001). Def ...

随机推荐

  1. onscreen and offscreen

    本文来自stackoverflow一位网友的解答,感觉非常不错就摘录了. --------------------------------------------------------------- ...

  2. mongodb 配置单实例与双实例

    环境: centos6.5 192.168.16.70 配置单实例mongodb:[root@www soft]# tar xf mongodb-linux-x86_64-rhel62-3.2.7.t ...

  3. 【WinForm】创建自定义控件(转)

    转自:http://www.cnblogs.com/bomo/archive/2012/12/09/2810559.html 虽然VS为我们提供了很多控件可以使用,但有时候这些控件仍然不能满足我们的要 ...

  4. cocos2d-js添加广点通插屏(通过jsb反射机制)

    1.把广点通的jar包加入libs文件夹 2.修改AndroidManifest.xml文件 添加权限: <uses-permission android:name="android. ...

  5. error LNK2022: metadata operation failed (801311D6) : Differing number of methods in duplicated types

    本文主要是记录一个C++编译错误的解决方案,具体错误请看本文标题. 这个错误主要是由Managed C++的增量编译导致的,这是VS 2008的一个bug,在VS 2010已经修复,我使用的正式201 ...

  6. distributed OSGI demo

    今天继续<OSGi原理与最佳实践>.看到第四章.做 HelloWorld-cxf 的样例 照着样例敲来着,整个样例敲完了,执行.一直报错, ----------------这里是解决方法- ...

  7. Ruby 文件 FILE

    FileUtils.makedirs(LOCAL_DIR) unless File.exists?LOCAL_DIR require 'fileutils' Dir.mkdir(DATA_DIR) u ...

  8. 登录令牌 Token 介绍

     Token值介绍 token 值: 登录令牌.利用 token 值来判断用户的登录状态.类似于 MD5 加密之后的长字符串. 用户登录成功之后,在后端(服务器端)会根据用户信息生成一个唯一的值.这个 ...

  9. h大数据

    安全认证 hw HBase安全认证(创建HBaseHolder时认证) String userPrincipal = FeatureContext.INSTANCE.getOrElse(Constan ...

  10. laravel基础课程---10、数据库基本操作(如何使用数据库)

    laravel基础课程---10.数据库基本操作(如何使用数据库) 一.总结 一句话总结: 1.链接数据库:.env环境配置里面 2.执行数据库操作:DB::table('users')->up ...