这道题非常巧妙!!!

我们进行点分治的时候,算出当前子节点的所有子树中的节点,到当前节点节点的儿子节点的距离,如下图意思就是

当前节点的红色节点,我们要求出红色节点的儿子节点绿色节点,所有绿色的子树节点的到当绿色的点权乘积

有如下的情况:

1*5*7  3*6*7

2*5*7 4*6*7

然后我们要想办法查询其他链上到红色节点的乘积,比如蓝色的所有子树到红色节点的乘积,以及这些乘积对应的链的尾部节点。

因此我们需要用逆元求,因为我们并不容易直接求出一条链上所有节点的点权乘积为K的链,但是我们可以通过搜索出所有当前节点的乘积,然后查询逆元长度的链条是否存在,更加方便的求出答案。

比较抽象。。。多打几遍就懂了。。。

#pragma comment(linker,"/STACK:102400000,102400000")
#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<string.h>
#define LL long long
using namespace std;
const int INF = 0x3f3f3f3f;
const int maxx = 2e5+6;
const int MOD = 1000003;
int ver[maxx],head[maxx],Next[maxx],q[maxx];
int sz[maxx],mp[MOD+10],vis[maxx],a[maxx],id[maxx];
int inv[MOD+10];
int tot,mx,size,root,l,r,ansx,ansy,k;
inline int read()
{
int x=0;char ch=getchar();
while(ch<'0'||ch>'9')ch=getchar();
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x;
}
void add(int u,int v){
ver[++tot]=v;Next[tot]=head[u];head[u]=tot;
ver[++tot]=u;Next[tot]=head[v];head[v]=tot;
}
///求重心
void getroot(int u,int fa){
sz[u]=1;
int num=0;
for (int i=head[u];i;i=Next[i]){
int v=ver[i];
if (v==fa||vis[v])continue;
getroot(v,u);
sz[u]+=sz[v];
num=max(num,sz[v]);
}
num=max(num,size-sz[u]);
if (num<mx)mx=num,root=u;
}
///求子树的链的点权积
void getdis(int u,int fa,int val){
q[++r]=val;
id[r]=u;
for (int i=head[u];i;i=Next[i]){
int v=ver[i];
if (v==fa || vis[v])continue;
getdis(v,u,(LL)val*a[v]%MOD);
}
}
///检查逆元所对应的长度是否存在
void check(int x,int val){
int w=(LL)inv[val]*k%MOD;
int y=mp[w];
if (y==0||x==y)return;
if (x>y)swap(x,y);
if (x<ansx || (x==ansx && y<ansy)){
ansx=x;
ansy=y;
}
return;
}
void solve(int u){
vis[u]=1;
mp[a[u]]=u;
///求出当前节点的子树对应的点权积
for (int i=head[u];i;i=Next[i]){
int v=ver[i];
if (vis[v])continue;
r=0;
getdis(v,u,a[v]);
for (int j=1;j<=r;j++){
check(id[j],q[j]);
}
///把所有子树链的乘积再乘上当前节点的权值,
///这样保存使得另外一颗子树的一条链能够轻松找到另外一条不和自己在同一个子树内且点权乘积为K的长度
for (int j=1;j<=r;j++){
q[j]=(LL)q[j]*a[u]%MOD;
int now=mp[q[j]];
if (now==0 || now>id[j]){
mp[q[j]]=id[j];
}
}
}
mp[a[u]]=0;
///要继续点分治,父亲节点的信息以及没有用了
for (int i=head[u];i;i=Next[i]){
int v=ver[i];
if(vis[v])continue;
r=0;
l=1;
getdis(v,u,(LL)a[u]*a[v]%MOD);
for(int j=1;j<=r;j++){
mp[q[j]]=0;
}
}
for (int i=head[u];i;i=Next[i]){
int v=ver[i];
if (vis[v])continue;
size=sz[v];
mx=INF;
getroot(v,0);
solve(root);
}
}
int main(){
inv[1]=1;
for (int i=2;i<MOD;i++){
inv[i]=(LL)(MOD-(MOD/i))*inv[MOD%i]%MOD;
}
int n;
while(~scanf("%d%d",&n,&k)){
for(int i=1;i<=n;i++){
a[i]=read();
}
tot=0;
memset(mp,0,sizeof(mp));
int u,v;
for (int i=1;i<=n;i++){
vis[i]=0;
head[i]=0;
}
tot=0;
for (int i=1;i<n;i++){
u=read();
v=read();
add(u,v);
}
ansx=INF;
ansy=INF;
mx=INF;
size=n;
getroot(1,0);
solve(root);
if (ansx==INF){
printf("No solution\n");
}else {
printf("%d %d\n",ansx,ansy);
}
}
return 0;
}

  

E - D Tree HDU - 4812 点分治+逆元的更多相关文章

  1. HDU 4812:D Tree(树上点分治+逆元)

    题目链接 题意 给一棵树,每个点上有一个权值,问是否存在一条路径(不能是单个点)上的所有点相乘并对1e6+3取模等于k,输出路径的两个端点.如果存在多组答案,输出字典序小的点对. 思路 首先,(a * ...

  2. HDU 4812 (点分治)

    题目:https://vjudge.net/contest/307753#problem/E 题意:给你一颗树,树上每个点都有个权值,现在问你是否存在 一条路径的乘积 mod 1e6+3  等于 k的 ...

  3. D Tree HDU - 4812

    https://vjudge.net/problem/HDU-4812 点分就没一道不卡常的? 卡常记录: 1.求逆元忘开longlong 2.把solve中分离各个子树的方法,由“一开始全部加入,处 ...

  4. hdu 4812 DTree (点分治)

    D Tree Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 102400/102400 K (Java/Others)Total S ...

  5. HDU 4812 D Tree

    HDU 4812 思路: 点分治 先预处理好1e6 + 3以内到逆元 然后用map 映射以分治点为起点的链的值a 成他的下标 u 然后暴力跑出以分治点儿子为起点的链的值b,然后在map里查找inv[b ...

  6. HDU 4871 Shortest-path tree 最短路 + 树分治

    题意: 输入一个带权的无向连通图 定义以顶点\(u\)为根的最短路生成树为: 树上任何点\(v\)到\(u\)的距离都是原图最短的,如果有多条最短路,取字典序最小的那条. 然后询问生成树上恰好包含\( ...

  7. hdu 5016 点分治(2014 ACM/ICPC Asia Regional Xi'an Online)

    Mart Master II Time Limit: 12000/6000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)T ...

  8. H - Partial Tree HDU - 5534 (背包)

    题目链接: H - Partial Tree  HDU - 5534 题目大意:首先是T组测试样例,然后n个点,然后给你度数分别为(1~n-1)对应的不同的权值,然后问你在这些点形成树的前提下的所能形 ...

  9. 【AtCoder3611】Tree MST(点分治,最小生成树)

    [AtCoder3611]Tree MST(点分治,最小生成树) 题面 AtCoder 洛谷 给定一棵\(n\)个节点的树,现有有一张完全图,两点\(x,y\)之间的边长为\(w[x]+w[y]+di ...

随机推荐

  1. 木卯先生的笔记---Date类、DateFormat类和Calendar类

    1.Date类 1.1 简介 Date类是 java.util 包下面的类,表示特定的瞬间,精确到毫秒. 1.2 方法 1.2.1 Date() 构造方法 public Date() :分配 Date ...

  2. day 52

    目录 静态文件配置 form表单默认是get请求 request方法的初识 数据库的迁移命令 静态文件配置 默认情况下所有的html文件都放在templates文件夹内 什么是静态文件 网站所使用到的 ...

  3. Linux下读写UART串口的代码

    Linux下读写UART串口的代码,从IBM Developer network上拿来的东西,操作比較的复杂,就直接跳过了,好在代码能用,记录一下- 两个实用的函数- //////////////// ...

  4. shell linux基本命令实例、笔记

    1. 在当前文件夹下.查找20分钟内,被訪问过的文件, 并将文件的详情显示出来: find ./ -name '*.log' -mmin -20 -exec ls -l {} \;   当然,须要指出 ...

  5. 模板方法(Template Method)(父类声明算法骨架,子类具体不同实现)

    在阎宏博士的<JAVA与模式>一书中开头是这样描述模板方法(Template Method)模式的: 模板方法模式是类的行为模式.准备一个抽象类,将部分逻辑以具体方法以及具体构造函数的形式 ...

  6. 2019.10.20 csp-s模拟测试 lrd试题 反思总结

    赶进度赶进度,丢个代码两三句备注一下完事了. day1: 前面两道题没实际写代码怕印象不深所以描述一下大意. T1: 题目大意:给出两个数&.|.^的结果(可能只给出其中某一项或者某两项),求 ...

  7. Nginx 日志切割后无法记日志

    日志切割会向Nginx Pid发送一个信号重新打开日志文件,如果nginx.conf没有配置PID,切割日志后找不到PID文件,就会出问题

  8. redis的安装,以及主从实现同步

    Redis的主从复制功能非常强大,一个master可以拥有多个slave,而一个slave又可以拥有多个slave,如此下去,形成了强大的多级服务器集群架构.下面我演示下怎样在多台服务器上进行Redi ...

  9. 【JZOJ3640】【COCI2014】utrka

    Mission 2<=N<=300,2<=M<=N∗(N−1) Solution SPFA. 由于只是二元关系,所以条件随便写. 具体来说,如果是u⇒v. 若v的最大领先时间还 ...

  10. 大合集 | 9 场 Dubbo Meetup 回顾视频和PPT下载

    2018年2月16日,Dubbo 加入 Apache 基金会孵化器,在随后的那个夏天,我们开始在全国(北京.上海.深圳.成都.杭州)和社区的用户们见面.认识.交个朋友,将社区的最新动态.Dubbo 的 ...