CodeForces - 990G (点分治+链表计数)
题目: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 (点分治+链表计数)的更多相关文章
- Codeforces 990G 点分治+暴力
题意:给出一棵点带权的树,求i\(\in\)[1,200000]所有路径的上点权的gcd==i的个数. 考虑点分治,对于一棵以u为根的子树,如何统计经过u的路径的答案? 显然既然是经过点u的路径,那么 ...
- Codeforces 293E 点分治+cdq
Codeforces 293E 传送门:https://codeforces.com/contest/293/problem/E 题意: 给你一颗边权一开始为0的树,然后给你n-1次操作,每次给边加上 ...
- CodeForces 176B Word Cut (计数DP)
Word Cut Time Limit:2000MS Memory Limit:262144KB 64bit IO Format:%I64d & %I64u Submit St ...
- 51NOD 1810 连续区间 分治 区间计数
1810 连续区间 基准时间限制:1.5 秒 空间限制:131072 KB 分值: 80 区间内所有元素排序后,任意相邻两个元素值差为1的区间称为“连续区间” 如:3,1,2是连续区间,但3, ...
- codeforces 161D 点分治
传送门:https://codeforces.com/problemset/problem/161/D 题意: 求树上点对距离恰好为k的点对个数 题解: 与poj1741相似 把点分治的模板改一下即可 ...
- Codeforces 475D CGCDSSQ(分治)
题意:给你一个序列a[i],对于每个询问xi,求出有多少个(l,r)对使得gcd(al,al+1...ar)=xi. 表面上是询问,其实只要处理出每个可能的gcd有多少个就好了,当左端点固定的时候,随 ...
- Codeforces 558E A Simple Task (计数排序&&线段树优化)
题目链接:http://codeforces.com/contest/558/problem/E E. A Simple Task time limit per test5 seconds memor ...
- Codeforces 888G(分治+trie)
按位贪心,以当前考虑位是0还是1将数分成两部分,则MST中这两部分之间只会存在一条边,因为一旦有两条或以上的边,考虑两条边在原图中所成的环,显然这两条边有一条是环上的权值最大边,不会出现在MST中.则 ...
- Codeforces 888G Xor-MST - 分治 - 贪心 - Trie
题目传送门 这是一条通往vjudge的高速公路 这是一条通往Codeforces的高速公路 题目大意 给定一个$n$阶完全图,每个点有一个权值$a_{i}$,边$(i, j)$的权值是$(a_{i}\ ...
随机推荐
- 《图解设计模式》读书笔记2-2 Factory Method模式
目录 类图 代码 角色介绍 思想 类图 代码 //产品类,任意可"use"的产品都可继承该类 public abstract class Product { public abst ...
- 《图解设计模式》读书笔记1-2 Adapter模式
目录 Adapter即适配器,可以类比为将220V的电压的电源转为5V电压的手机充电器,起转换的作用. 明确概念: Adaptee:被适配者,即220v电压的电源 Adapter:适配器,即手机充电器 ...
- delphi 牛逼 了 app (已在软件界掀起波澜)10分钟10行代码做出让人惊叹的程序
(已在软件界掀起波澜)10分钟10行代码做出让人惊叹的程序 http://v.qq.com/x/page/m0328h73bs7.html?ptag=bbs_csdn_net
- Unity3D移动端电量与wifi信号的获取
移动端游戏中无法看到电量与wifi信号对于玩家来说是很困扰的事. 关于这个问题安卓与iOS有不同的方法 电量 安卓 安卓获取电量有两种方法,一种是读取安卓手机里的一个文件,一种是利用安卓与Unity互 ...
- HTML5--浏览器全屏操作、退出全屏、是否全屏
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- tp增删改查
增: 向数据库增加新的数据,这里增是纯粹的增添数据,如果新增的数据包含主键,并且该主键已经在数据库存在,则无法新增数据的. //M("User") 用于高效实例化一个数据模型(M ...
- mybatis小总结
mybatis是一个持久层的框架,是一个不完全的orm框架.sql语句需要程序员自己去编写,但是mybatis也有映射(输入参数映射,输出结果映射) mybatis入门门槛不高,学习成本低,让程序员把 ...
- Webpack的使用指南-Webpack的常用解决方案
说是解决方案实际上更像是webpack的插件索引. 写这一篇的目的是为了形成一个所以,将来要用时直接来查找即可. 1.自动构建HTML,可压缩空格,可给引用的js加版本号或随机数:html-webpa ...
- mysql-时间格式
SELECT DATE_FORMAT('2019-1-1 15:1:1.099','%Y-%m-%d %H:%i:%s.%f') -- 2019-01-01 15:01:01.099000 %a 缩 ...
- 广播模式下的生产者与消费者fanout模式
生产者 #coding=utf-8 import pika import sys connection = pika.BlockingConnection(pika.ConnectionParamet ...