题目:https://vjudge.net/contest/307753#problem/J

题意:一棵树,每个点都有个权值,现在问你,树上gcd每个不同的数有多少个

思路:点分治,首先范围只有 1e5,然后我们记录一条路径的gcd,我们在重心确定后找路径,每到gcd一个数,这条路径必然是父亲节点的因子,一个数的因子不同的个数很少,其实就相当于是几个数的不同因子数,所以gcd路径不同的个数肯定很少,我们就可以在遍历子树的时候直接暴力之前出现过的路径值了,复杂度 应该是 O(n*logn*logn)的,

这题时间卡的特别紧,我本来使用map记录不同数的个数,发现超时,我认为是多了个log的原因,我就改成了链表O(1)取,但是仔细想想其实map的log其实是按节点数来的,我gcd不同的数很少,其实这个log趋近于O(1),真正的原因-输入挂(坑的死)

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
#include<vector>
#include<queue>
#include<map>
#define maxn 200005
#define mod 0x3f3f3f3f
using namespace std;
typedef long long ll;
struct edge{
int to,next;
}e1[*maxn];
struct node{
ll next;
ll val;
ll bj;
}flag[maxn];
ll da;
vector<ll> mp[maxn],xx[maxn];//存下图
ll e[maxn];
ll e2[*maxn];
bool vis[maxn];//标记曾经使用过的重心
ll maxsize[maxn],dis[maxn],d[maxn],yj[maxn],last[maxn];//maxsize 当前节点的最大子树
ll siz[maxn],xd[maxn];// dis 到重心的距离 d 出现过的距离
ll n,m,k,rt,sum,qe,qe2,ans1,ans2,cnt,head; // siz 当前节点的子树个数 e 出现的距离 rt代表当前重心
inline void read(ll &x) {
x=; char c=getchar();
while(c>''||c<'') c=getchar();
while(c<=''&&c>='') x=(x<<)+(x<<)+c-'',c=getchar();
}
void find(ll x,ll f){//找出重心
siz[x]=;
maxsize[x]=;
for(int i=last[x];i;i=e1[i].next){
ll v=e1[i].to;
if(v==f||vis[v]) continue;//vis数组标记曾经使用过的重心
find(v,x);
siz[x]+=siz[v];
maxsize[x]=max(maxsize[x],siz[v]);
}
maxsize[x]=max(maxsize[x],sum-siz[x]);//节点总数减去当前的子树数=以当前节点为根的父亲点子树数
if(maxsize[x]<maxsize[rt]){
rt=x;
}
}
void insert(int u,int v)
{
e1[++cnt].to=v;e1[cnt].next=last[u];last[u]=cnt;
e1[++cnt].to=u;e1[cnt].next=last[v];last[v]=cnt;
}
void get_dis(ll x,ll f,ll len,ll root){ yj[len]++;
ll t=head;
while(t!=-){
yj[__gcd(t,len)]+=flag[t].val;
t=flag[t].next;
}
e[qe]=len;
qe++;
for(int i=last[x];i;i=e1[i].next){
ll v=e1[i].to;
if(v==f||vis[v]) continue;
//dis[q.first]=(dis[x]+len)%3;
get_dis(v,x,__gcd(len,xd[v]),root);
}
}
void divide(ll x){
vis[x]=;
//printf("rt=%lld ans1=%lld\n",x,ans1);
for(int i=last[x];i;i=e1[i].next){
ll v=e1[i].to;
qe=;
if(vis[v]) continue;
//dis[x]=q.second;
get_dis(v,x,__gcd(xd[x],xd[v]),x);
for(int j=;j<qe;j++){
if(head==-){
head=e[j];
flag[e[j]].val=;
flag[e[j]].next=-;
flag[e[j]].bj=;
}
else if(flag[e[j]].bj==){
flag[e[j]].val=;
flag[e[j]].next=head;
flag[e[j]].bj=;
head=e[j];
}
else{
flag[e[j]].val++;
}
}
}
ll t=head;
while(t!=-){
flag[t].bj=;
t=flag[t].next;
}
head=-;
//qe2=0;
for(int i=last[x];i;i=e1[i].next){
ll q=e1[i].to;
if(vis[q]) continue;
//if(da>0) break;
sum=siz[q];
rt=;
maxsize[rt]=mod;
find(q,x);
divide(rt);
}
// vis[x]=0;
}
void init(){
ans1=;ans2=;
head=-;
//for(int i=0;i<=n+1;i++) mp[i].clear();
for(int i=;i<=n+;i++) vis[i]=;
//for(int i=0;i<=n+1;i++) flag[i]=0;
for(int i=;i<=n+;i++) yj[i]=;
}
int main(){
ll t;
read(n);
ll a,b,c;
init();
ll xx;
for(int i=;i<=n;i++){
read(xd[i]);
yj[xd[i]]++;
}
for(int i=;i<=n-;i++){
read(a);
read(b);
insert(a,b);
}
sum=n;//当前节点数
rt=;
maxsize[]=mod;//置初值
find(,);
divide(rt);
for(int i=;i<maxn;i++){
if(yj[i]==) continue;
cout<<i<<" "<<yj[i]<<"\n";
//printf("%I64d %I64d\n",i,yj[i]);
}
}

CodeForces - 990G (点分治+链表计数)的更多相关文章

  1. Codeforces 990G 点分治+暴力

    题意:给出一棵点带权的树,求i\(\in\)[1,200000]所有路径的上点权的gcd==i的个数. 考虑点分治,对于一棵以u为根的子树,如何统计经过u的路径的答案? 显然既然是经过点u的路径,那么 ...

  2. Codeforces 293E 点分治+cdq

    Codeforces 293E 传送门:https://codeforces.com/contest/293/problem/E 题意: 给你一颗边权一开始为0的树,然后给你n-1次操作,每次给边加上 ...

  3. CodeForces 176B Word Cut (计数DP)

    Word Cut Time Limit:2000MS     Memory Limit:262144KB     64bit IO Format:%I64d & %I64u Submit St ...

  4. 51NOD 1810 连续区间 分治 区间计数

    1810 连续区间 基准时间限制:1.5 秒 空间限制:131072 KB 分值: 80     区间内所有元素排序后,任意相邻两个元素值差为1的区间称为“连续区间” 如:3,1,2是连续区间,但3, ...

  5. codeforces 161D 点分治

    传送门:https://codeforces.com/problemset/problem/161/D 题意: 求树上点对距离恰好为k的点对个数 题解: 与poj1741相似 把点分治的模板改一下即可 ...

  6. Codeforces 475D CGCDSSQ(分治)

    题意:给你一个序列a[i],对于每个询问xi,求出有多少个(l,r)对使得gcd(al,al+1...ar)=xi. 表面上是询问,其实只要处理出每个可能的gcd有多少个就好了,当左端点固定的时候,随 ...

  7. Codeforces 558E A Simple Task (计数排序&&线段树优化)

    题目链接:http://codeforces.com/contest/558/problem/E E. A Simple Task time limit per test5 seconds memor ...

  8. Codeforces 888G(分治+trie)

    按位贪心,以当前考虑位是0还是1将数分成两部分,则MST中这两部分之间只会存在一条边,因为一旦有两条或以上的边,考虑两条边在原图中所成的环,显然这两条边有一条是环上的权值最大边,不会出现在MST中.则 ...

  9. Codeforces 888G Xor-MST - 分治 - 贪心 - Trie

    题目传送门 这是一条通往vjudge的高速公路 这是一条通往Codeforces的高速公路 题目大意 给定一个$n$阶完全图,每个点有一个权值$a_{i}$,边$(i, j)$的权值是$(a_{i}\ ...

随机推荐

  1. 批量执行SQL脚本

    新建文件夹all_sql,并将需要执行的sql脚本放入其中. 新建bat脚本,执行即可,ORACLE 也可改Mysql,按需:如下 ::echo off :: @echo off echo 开始执行数 ...

  2. LATERAL VIEW 语法

    LATERAL VIEW 使用语法 原文链接: https://www.deeplearn.me/2892.html select a.id, b.son_order_path from f_jz_c ...

  3. Vagrant 手册之 box - 概述

    原文地址 box 是 Vagrant 环境中使用的包格式.box 可以在 Vagrant 支持的所有平台上被任何人使用,从而提供相同的工作环境. vagrant box 工具提供了管理 box 的所有 ...

  4. Oracle11g安装步骤

    plsql安装等:https://blog.csdn.net/li66934791/article/details/83856225      https://www.cnblogs.com/gaoz ...

  5. 怎么查看keras 或者 tensorflow 正在使用的GPU

    查看keras认得到的GPU from keras import backend as K K.tensorflow_backend._get_available_gpus() Out[28]: [' ...

  6. 《STL源码剖析》——第五、六:关联容器与算法

    第五章.关联容器  5.0.关联容器 标准的STL关联式容器分为set(集合)和map(映射表)两大类,以及这两大类的衍生体multiset(多键集合)和multimap(多键映射表).这些容器的底层 ...

  7. Collection -集合祖宗的常用七种共性方法

    package cn.learn.collection; import java.util.ArrayList; import java.util.Collection; /* 在java.util. ...

  8. kmp(前中后最长相同长度)

    http://acm.hdu.edu.cn/showproblem.php?pid=4763 Theme Section Time Limit: 2000/1000 MS (Java/Others)  ...

  9. JS的video在手机上有些手机能播放,而有些不能原因

    一,一开始我video是这样写的,直接给地址,然后有很多手机却不能播放,或者说卡在一开始的页面,是什么原因呢? <video id='video' > <source src='xx ...

  10. JS面向对象——组合使用构造函数模型与原型模型

    该模型为创建自定义类型最常用的方式. <!DOCTYPE html> <html> <head> <title>组合使用构造函数模型和原型模型</ ...