题目: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. Vagrant 手册之 Vagrantfile - 最低版本

    原文地址 可以在 Vagrantfile 中指定一组 Vagrant 的版本,以强制人们使用带有 Vagrantfile 的特定版本的 Vagrant.这可以帮助解决使用带有 Vagrantfile ...

  2. JavaScript 高级程序设计(第3版)第一章 (js简介)

    1.我比js早一年 2.web浏览器是ECMAScript实现的宿主环境之一. 其它实现ECMAScript的宿主环境包括Node和Adobe Flash 3.ECMAScript主要规定js的组成部 ...

  3. #C语言l作业04

    这个作业属于哪个课程** C语言程序设计ll 这个作业的要求 (https://edu.cnblogs.com/campus/zswxy/SE2019-4/homework/9776) 我在这个课程的 ...

  4. UI自动化处理文件上传

    UI自动化处理文件上传 import win32guiimport win32con def set_uploader(self, file_path): sleep(2) self.file_pat ...

  5. IDEA远程代码实时同步(可以自动实时同步)

    前言 开发时一般的平台都是windows,但windows对开发极其不友好,一般都会在本地开启虚拟机,安装上linux环境进行项目的部署测试.下面介绍一种windows主机与linux虚拟机代码同步的 ...

  6. 什么是SpringMvc

    1.什么是SpringMvc? SpringMvc是spring的一个模块 基于MVC的一个框架 无需中间整合层来整合 什么是MVC ?mvc在b/s下的应用: 首先请求发送request请求到C(c ...

  7. shuoj 1 + 2 = 3? (二分+数位dp)

    题目传送门 1 + 2 = 3? 发布时间: 2018年4月15日 22:46   最后更新: 2018年4月15日 23:25   时间限制: 1000ms   内存限制: 128M 描述 埃森哲是 ...

  8. BUUCTF--reverse2

    测试文件:https://buuoj.cn/files/ef0881fc76e5bcd756b554874ef99bec/e8722e94-93d7-45d5-aa06-a7aa26ce01a1.ra ...

  9. 微软Visual Studio Code基本特征

    Visual Studio Code它的核心功能还是作为一个代码编辑器.和其他的代码编辑器一样,VScode采取通用的UI和布局,浏览器在左边,显示所有的文件和文件夹,右边你打开的文件的编辑页面. 文 ...

  10. axios 如何获取下载文件的进度条

    exportFun(){         let _that = this         const instance = this.axios.create({           onDownl ...