题目: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. Linux实用技巧--隧道

    平时开发过程中,可能会遇到一些网络问题,比如npm install 一些依赖包.本地电脑是可以,没有问题.但是测试环境服务器,由于公司内部网络安全限制,不可以随意访问外部网络.因此下载一个依赖包就变得 ...

  2. Vagrant 入门 - 清理(teardown)

    原文地址 我们现在有一个功能齐全的虚拟机,可以用于基本 Web 开发.但如果现在需要更换设备,或者在另一个项目上工作,如何清理我们的开发环境? 借助 Vagrant,可以暂停(suspend),停止( ...

  3. Git012--Bug&Feature分支

    一.Git--Bug分支 软件开发中,bug就像家常便饭一样.有了bug就需要修复,在Git中,由于分支是如此的强大,所以,每个bug都可以通过一个新的临时分支来修复,修复后,合并分支,然后将临时分支 ...

  4. Java thread(3)

    线程间的调度策略 通常是选择优先级高的线程,但是若发生以下情况则终止线程的运行:    1 调用yield 让出对cpu的占用权. 2 调用sleep 3 线程由于I/O操作而受阻 4 更高优先级的线 ...

  5. JSP基础--九大内置对象

    JSP九大内置对象 Object findAttribute(String name):依次在page.request.session.application范围查找名称为name的数据,如果找到就停 ...

  6. jQuery基础--动画操作

    三组基本动画 <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset=" ...

  7. vc code 一个非常不错的插件

    https://marketplace.visualstudio.com/items?itemName=CoenraadS.bracket-pair-colorizer 这个是地址,前提下是安装了vc ...

  8. 什么是HTTP协议?常用的状态码有哪些?

    一.HTTP简介 HTTP协议是Hyper Text Transfer Protocol(超文本传输协议)的缩写,是用于从万维网(WWW:World Wide Web )服务器传输超文本到本地浏览器的 ...

  9. 【洛谷p1036】选数

    (一定要声明我太蒟了,这个题扣了一上午……) 算法标签: …… dfs真的不是我所擅长的qwq,这道题的思路其实很简单,就是先dfs搜索所有可能的和,然后判断是不是质数.说着好说,然鹅并不好写: 第一 ...

  10. C# 字符串Trim进阶

    private void button1_Click(object sender, EventArgs e) {//去掉字符串头尾指定字符 string MyInfo= "--中华人民共和国 ...