hdoj4812 D Tree(点分治)
题目链接:https://vjudge.net/problem/HDU-4812
题意:给定一颗带点权的树,求是否存在一条路经的上点的权值积取模后等于k,如果存在多组点对,输出字典序最小的。
思路:
点分治模板题。按照套路,找重心,求出子树中节点到重心的权值积取模后的值dis[i](包括重心的权值,也不可以不包括,一样的),用id[j]记录该路径的端点,用的是点分治的第二种写法。递归时,用桶mine[i]记录到重心权值积为i的最小编号。然后查找时,对dis[j],满足要求的tmp为:tmp*dis[j]%MOD=k*V[u],因为我们的dis中包括重心的权值,所以重心的权值被乘了2次。然后用到了逆元,tmp=k*V[u]%MOD*inv[dis[j]]%MOD。更新完答案后就更新桶。
因为没看清题目,题目求得点对(a,b)是a<b,而我以为(a,a)也满足,然后就找了两小时bug,崩溃到想锤电脑QAQ...。
AC代码:
#include<cstdio>
#include<algorithm>
#include<cctype>
#include<cstring>
using namespace std; inline int read(){
int x=,f=;char ch=;
while(!isdigit(ch)) {f|=ch=='-';ch=getchar();}
while(isdigit(ch)) x=(x<<)+(x<<)+(ch^),ch=getchar();
return f?-x:x;
} typedef long long LL;
const int maxn=1e5+;
const int MOD=1e6+;
const int maxk=1e6+;
const int inf=0x3f3f3f3f;
struct node1{
int v,nex;
}edge[maxn<<]; struct node2{
int x,y;
node2(){x=y=;}
node2(int x,int y):x(x),y(y){}
}ans; bool operator < (node2 a,node2 b){
if(a.x==b.x) return a.y<b.y;
return a.x<b.x;
} int n,k,cnt,head[maxn],sz[maxn],mson[maxn],Min,root,size;
int vis[maxn],mine[maxk],id[maxn],t,tt;
LL V[maxn],dis[maxn],inv[maxk]; void init(){
inv[]=;
for(int i=;i<maxk;++i)
inv[i]=(MOD-MOD/i)*inv[MOD%i]%MOD;
} void adde(int u,int v){
edge[++cnt].v=v;
edge[cnt].nex=head[u];
head[u]=cnt;
} void getroot(int u,int fa){
sz[u]=,mson[u]=;
for(int i=head[u];i;i=edge[i].nex){
int v=edge[i].v;
if(vis[v]||v==fa) continue;
getroot(v,u);
sz[u]+=sz[v];
mson[u]=max(mson[u],sz[v]);
}
mson[u]=max(mson[u],size-sz[u]);
if(mson[u]<Min) Min=mson[u],root=u;
} void getdis(int u,int fa,LL len){
dis[++t]=len,id[t]=u;
for(int i=head[u];i;i=edge[i].nex){
int v=edge[i].v;
if(vis[v]||v==fa) continue;
getdis(v,u,len*V[v]%MOD);
}
} void solve(int u){
mine[V[u]]=u,t=;
for(int i=head[u];i;i=edge[i].nex){
int v=edge[i].v;
if(vis[v]) continue;
tt=t;
getdis(v,u,V[u]*V[v]%MOD);
for(int j=tt+;j<=t;++j){
LL tmp=1LL*k*V[u]%MOD*inv[dis[j]]%MOD;
if(mine[tmp]==inf) continue;
node2 other;
if(mine[tmp]<id[j]) other.x=mine[tmp],other.y=id[j];
else other.x=id[j],other.y=mine[tmp];
if(other<ans) ans=other;
}
for(int j=tt+;j<=t;++j)
mine[dis[j]]=min(mine[dis[j]],id[j]);
}
mine[V[u]]=inf;
for(int i=;i<=t;++i)
mine[dis[i]]=inf;
} void fenzhi(int u,int ssize){
vis[u]=;
solve(u);
for(int i=head[u];i;i=edge[i].nex){
int v=edge[i].v;
if(vis[v]) continue;
Min=inf,root=;
size=sz[v]<sz[u]?sz[v]:(ssize-sz[u]);
getroot(v,);
fenzhi(root,size);
}
} int main(){
init();
memset(mine,0x3f,sizeof(mine));
while(~scanf("%d%d",&n,&k)){
cnt=;
ans.x=ans.y=n+;
for(int i=;i<=n;++i)
head[i]=vis[i]=;
for(int i=;i<=n;++i){
int tmp=read();
V[i]=tmp;
}
for(int i=;i<n;++i){
int u=read(),v=read();
adde(u,v);
adde(v,u);
}
Min=inf,root=,size=n;
getroot(,);
fenzhi(root,n);
if(ans.x==n+)
printf("No solution\n");
else
printf("%d %d\n",ans.x,ans.y);
}
return ;
}
hdoj4812 D Tree(点分治)的更多相关文章
- 【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 ...
- POJ 1741 Tree 树分治
Tree Description Give a tree with n vertices,each edge has a length(positive integer less than 1 ...
- [bzoj 1468][poj 1741]Tree [点分治]
Description Give a tree with n vertices,each edge has a length(positive integer less than 1001). Def ...
- 【CF434E】Furukawa Nagisa's Tree 点分治
[CF434E]Furukawa Nagisa's Tree 题意:一棵n个点的树,点有点权.定义$G(a,b)$表示:我们将树上从a走到b经过的点都拿出来,设这些点的点权分别为$z_0,z_1... ...
- POJ 1741 Tree(点分治点对<=k)
Description Give a tree with n vertices,each edge has a length(positive integer less than 1001). Def ...
- POJ 1741.Tree 树分治 树形dp 树上点对
Tree Time Limit: 1000MS Memory Limit: 30000K Total Submissions: 24258 Accepted: 8062 Description ...
- poj 1744 tree 树分治
Tree Time Limit: 1000MS Memory Limit: 30000K Description Give a tree with n vertices,each ed ...
- CF1039D You Are Given a Tree 根号分治,贪心
CF1039D You Are Given a Tree LG传送门 根号分治好题. 这题可以整体二分,但我太菜了,不会. 根号分治怎么考虑呢?先想想\(n^2\)暴力吧.对于每一个要求的\(k\), ...
随机推荐
- (三)根据向导创建MFC工程,事件的添加和删除
一,文档视图结构 文档:它是一个类,这个类专门用来存储数据 视图:它是一个类,这个类专门用来显示和修改数据 框架类:一个容器,这个容器装了视图 健完工程之后,类视图: 运行一下: 几个比较重要的函数 ...
- Codevs 2482 宝库通道 2007年省队选拔赛安徽
2482 宝库通道 2007年省队选拔赛安徽 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 大师 Master 题目描述 Description 探宝的旅程仍然继续中,由于你的帮助 ...
- shell tail 命令
#显示最后两行 tail -n - filename > newfilename #从开头显示到倒数第二行 head -n - filename > newfilename
- CSS子元素在父元素中水平垂直居中的几种方法
1. 水平居中(margin: auto;)子父元素宽度固定,子元素上设置 margin: auto; 子元素不能设置浮动,否则居中失效. #div1{ width: 300px; height: 3 ...
- hashcode(),equal()方法经典分析
首先,想要明白hashCode的作用,必须要先知道Java中的集合. 总的来说,Java中的集合(Collection)有两类,一类是List,再有一类是Set. 前者集合内的元素是有序的,元素可以重 ...
- mybatis 操作其他数据库的数据表
配置文件里面配置的数据库只是默认数据库,并不是只能操作默认数据库.(被自己蠢死了,唉) 1. 注解方式 使用BaseMapper方式操作数据表时,在表对应的实体类上的 @table 注解描述表名时加上 ...
- Qt控制台输出QString
有时候想在控制台输出我们想要的QString变量. 1.qDebug可以实现在控制台终端打印,但我们还是想使用C++中的std::cout<<variable This function ...
- 如何在linux中发送邮件,使用163邮箱发信。
linux中,可以使用mail命令往外发送邮件,在使用前,只需要指定如下简单配置即可,这里演示用 163.com 邮箱发送至 qq.com 编辑 /etc/mail.rc,写入下方的参数 se ...
- incredibuild(分布式任务软件)脚本
IncrediBuild 可以在Server段通过修改单个任务的进程上限来实现提升任务执行速度. IncredBuild本机版也可以用来进行本机实现多线程任务分发,这样可以充分利用多核资源. 提交分布 ...
- Android ListView多布局
使用listview多布局会出现一点问题: 由于多个item布局给单一的item布局是不一样的,使用起来,contentview的复用会出现问题. 避免出现问题的有这几个方法: 1.重写 getVie ...