题意:一棵带边权的树,边权可单边修改,问初始时和每次修改后有多少条路径$\gcd=1$

首先考虑用反演求答案,设$f(n)$为路径$\gcd=n$的路径条数,$g(n)$为路径$\gcd$是$n$倍数的路径条数,那么$g(n)=\sum\limits_{n|d}f(d)$,所以$f(n)=\sum\limits_{d|n}\mu\left(\frac dn\right)g(d)$,答案就是$f(1)=\sum\limits_{d}\mu(d)g(d)$

我们现在要求$g(d)$,先考虑没有修改怎么做,我们对每个$d$预处理出是$d$倍数的那些边(这里可以直接枚举边权的约数,因为边权$\leq10^6$)用这些边构图,答案就是每个连通块的$\binom{siz}2$之和,这里可以用并查集做

加上修改就只预处理那些不被修改的边,先用这些不被修改的边建并查集,每次对第$i$个询问,修改第$1\cdots i$条边的边权后再把这至多$q$条边插进并查集中,再统计答案

总时间复杂度貌似是$O(wq^2\log n)$???但是加一些小优化好像可以过...

#include<stdio.h>
#include<vector>
using namespace std;
typedef long long ll;
const int T=1000000;
int pr[T+10],mu[T+10];
bool np[T+10];
void sieve(){
	int i,j,M=0;
	mu[1]=1;
	for(i=2;i<=T;i++){
		if(!np[i]){
			pr[++M]=i;
			mu[i]=-1;
		}
		for(j=1;j<=M&&i*pr[j]<=T;j++){
			np[i*pr[j]]=1;
			if(i%pr[j]==0)break;
			mu[i*pr[j]]=-mu[i];
		}
	}
}
struct edge{
	int x,y,w;
}E[100010];
struct ask{
	int i,v;
}Q[110];
bool del[100010],us[T+10];
vector<int>G[T+10];
ll C;
int fa[100010],dep[100010],siz[100010],M;
struct oper{
	int u,f,d,s;
	oper(int _u=0,int _f=0,int _d=0,int _s=0){u=_u;f=_f;d=_d;s=_s;}
}stk[200010];
void add(int u){
	stk[++M]=oper(u,fa[u],dep[u],siz[u]);
}
int get(int x){
	while(x!=fa[x])x=fa[x];
	return x;
}
void merge(int x,int y){
	x=get(x);
	y=get(y);
	if(x==y)return;
	if(dep[x]<dep[y])swap(x,y);
	add(x);
	add(y);
	fa[y]=x;
	if(dep[x]==dep[y])dep[x]++;
	C+=(ll)siz[x]*siz[y];
	siz[x]+=siz[y];
}
void roll(){
	int u=stk[M].u;
	fa[u]=stk[M].f;
	dep[u]=stk[M].d;
	siz[u]=stk[M].s;
	M--;
}
ll ans[110];
int val[100010];
int main(){
	int n,q,i,j,k,tM;
	ll tC;
	sieve();
	scanf("%d",&n);
	for(i=1;i<n;i++)scanf("%d%d%d",&E[i].x,&E[i].y,&E[i].w);
	scanf("%d",&q);
	for(i=1;i<=q;i++){
		scanf("%d%d",&Q[i].i,&Q[i].v);
		del[Q[i].i]=1;
	}
	for(i=1;i<n;i++){
		if(!del[i]){
			for(j=1;j*j<=E[i].w;j++){
				if(E[i].w%j==0){
					G[j].push_back(i);
					if(j*j!=E[i].w)G[E[i].w/j].push_back(i);
				}
			}
		}else{
			for(j=1;j*j<=E[i].w;j++){
				if(E[i].w%j==0)us[j]=us[E[i].w/j]=1;
			}
		}
	}
	for(i=1;i<=q;i++){
		for(j=1;j*j<=Q[i].v;j++){
			if(Q[i].v%j==0)us[j]=us[Q[i].v/j]=1;
		}
	}
	for(i=1;i<=n;i++){
		fa[i]=i;
		dep[i]=1;
		siz[i]=1;
	}
	for(i=1;i<=T;i++){
		if(mu[i]&&!(G[i].empty()&&!us[i])){
			C=0;
			M=0;
			for(int j:G[i])merge(E[j].x,E[j].y);
			tM=M;
			tC=C;
			for(j=1;j<=q;j++)val[Q[j].i]=E[Q[j].i].w;
			for(j=0;j<=q;j++){
				val[Q[j].i]=Q[j].v;
				C=tC;
				if(us[i]){
					for(k=1;k<=q;k++){
						if(val[Q[k].i]%i==0)merge(E[Q[k].i].x,E[Q[k].i].y);
					}
				}
				ans[j]+=mu[i]*C;
				while(M>tM)roll();
			}
			while(M)roll();
		}
	}
	for(i=0;i<=q;i++)printf("%lld\n",ans[i]);
}

[CODECHEF]TREECNT2的更多相关文章

  1. 【BZOJ-3514】Codechef MARCH14 GERALD07加强版 LinkCutTree + 主席树

    3514: Codechef MARCH14 GERALD07加强版 Time Limit: 60 Sec  Memory Limit: 256 MBSubmit: 1288  Solved: 490 ...

  2. 【BZOJ4260】 Codechef REBXOR 可持久化Trie

    看到异或就去想前缀和(⊙o⊙) 这个就是正反做一遍最大异或和更新答案 最大异或就是很经典的可持久化Trie,从高到低贪心 WA: val&(1<<(base-1))得到的并不直接是 ...

  3. codechef 两题

    前面做了这场比赛,感觉题目不错,放上来. A题目:对于数组A[],求A[U]&A[V]的最大值,因为数据弱,很多人直接排序再俩俩比较就过了. 其实这道题类似百度之星资格赛第三题XOR SUM, ...

  4. codechef January Challenge 2014 Sereja and Graph

    题目链接:http://www.codechef.com/JAN14/problems/SEAGRP [题意] 给n个点,m条边的无向图,判断是否有一种删边方案使得每个点的度恰好为1. [分析] 从结 ...

  5. BZOJ3509: [CodeChef] COUNTARI

    3509: [CodeChef] COUNTARI Time Limit: 40 Sec  Memory Limit: 128 MBSubmit: 339  Solved: 85[Submit][St ...

  6. CodeChef CBAL

    题面: https://www.codechef.com/problems/CBAL 题解: 可以发现,我们关心的仅仅是每个字符出现次数的奇偶性,而且字符集大小仅有 26, 所以我们状态压缩,记 a[ ...

  7. CodeChef FNCS

    题面:https://www.codechef.com/problems/FNCS 题解: 我们考虑对 n 个函数进行分块,设块的大小为S. 每个块内我们维护当前其所有函数值的和,以及数组中每个元素对 ...

  8. codechef Prime Distance On Tree(树分治+FFT)

    题目链接:http://www.codechef.com/problems/PRIMEDST/ 题意:给出一棵树,边长度都是1.每次任意取出两个点(u,v),他们之间的长度为素数的概率为多大? 树分治 ...

  9. BZOJ 3221: [Codechef FEB13] Obserbing the tree树上询问( 可持久化线段树 + 树链剖分 )

    树链剖分+可持久化线段树....这个一眼可以看出来, 因为可持久化所以写了标记永久化(否则就是区间修改的线段树的持久化..不会), 结果就写挂了, T得飞起...和管理员拿数据调后才发现= = 做法: ...

随机推荐

  1. ie8下input文字偏上select文字偏下

    1.ie8下input文字偏上 正常情况下input的显示情况如下 当设置input的高度时,就会出现文字不垂直居中偏上的情况,如图 解决方案 强input的行高line-height与其高度设置一致 ...

  2. js中的for in 循环

    1.数组 使用for in 遍历数组时,其索引被视为对象的属性,从而直接输出数组的索引 var arr = ["a","b","c"]; f ...

  3. CART算法(转)

    来源:http://www.cnblogs.com/pinard/p/6053344.html 作者:刘建平Pinard 对于C4.5算法,我们也提到了它的不足,比如模型是用较为复杂的熵来度量,使用了 ...

  4. 2017-2018-1 《Linux内核原理与设计》第十二周作业

    <linux内核原理与设计>第十二周作业 Sql注入基础原理介绍 分组: 和20179215袁琳完成实验 一.实验说明   SQL注入攻击通过构建特殊的输入作为参数传入Web应用程序,而这 ...

  5. linux中时间精度的获取问题【转】

    转自:http://www.xuebuyuan.com/877633.html 目前项目需要,需要对时间进行基准,基准的精度在微秒.下午老刘给我说不能用do_gettimeofday因为他的精度虽然可 ...

  6. Linux下用freetds执行SQL Server的sql语句和存储过程

    Linux下用freetds执行SQL Server的sql语句和存储过程 http://www.linuxidc.com/Linux/2012-06/61617.htm freetds相关 http ...

  7. 升级OS10.11系统后 Xcode6.4的变化少了个按钮 could not launch “Xcode” Xcode 插件安装

    升级OS10.11系统后 Xcode6.4的变化少了个按钮 could not launch “Xcode”  Xcode 插件安装 A:  升级10.11后Xcode 左上角模拟器选择菜单不在了   ...

  8. iframe自适应高度的方法

    不带边框的iframe因为能和网页无缝的结合从而不刷新新页面的情况下实现更新页面部分的数据成为可能,可是iframe却不像层那样可以收缩自如,iframe高度需要动态的调整需要JS来配合使用,只能通过 ...

  9. javascript方法--apply()

    今天琢磨了一下apply,以前对这个方法觉得比较懵,今天一琢磨确实觉得挺好玩的. 一开始把MDN的apply文档看了一遍,感觉不是很理解,而且有一些东西也是知道但是比较模糊,所以还是一步一步来,不懂查 ...

  10. Leetcode 之Binary Tree Postorder Traversal(45)

    层序遍历,使用队列将每层压入,定义两个队列来区分不同的层. vector<vector<int>> levelorderTraversal(TreeNode *root) { ...