列表

详情


NC205044. 小V和gcd树

描述

VMware实习生小V有一颗有n个结点的树,第结点具有点权。将边的边权定义为的最大公约数,即。有两种要处理的询问:

  1. 将结点的点权修改为,相应的边权也会发改变
  2. 回答在的路径上有多少条边的边权不超过

输入描述

第一行有两个整数,分别表示树的结点数和要处理的操作数
第二行给出n个整数,分别表示每个点初始点权
接下来n-1行每行2个整数  ,表示结点和结点之间具有边

接下来q行每行包含一个操作:

:如果操作用先给出一个整数1,然后紧跟着2个整数u,x,表示执行操作1

:如果操作先给出一个整数2,然后紧跟着3个整数u,v,k,表示执行操作2


输出描述

对每一个第2类询问,输出一个整数,为对应的答案。

示例1

输入:

6 5 
3 6 4 9 9 9 
2 1
3 2
4 2
5 4
6 5 
2 4 2 2 
2 1 3 5 
1 3 4 
2 3 6 3 
2 2 3 4

输出:

0 
2 
2 
1

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++14(g++5.4) 解法, 执行用时: 1211ms, 内存消耗: 2920K, 提交时间: 2020-05-17 00:20:36

#include<bits/stdc++.h>
using namespace std;
const int maxn=20010;
vector<int>G[maxn];
int a[maxn],fa[maxn],dep[maxn],w[maxn],m;
void dfs(int u)
{
    for(int v:G[u]){
        if(v==fa[u]) continue;
        fa[v]=u;
        w[v]=__gcd(a[u],a[v]);
        dep[v]=dep[u]+1;
        dfs(v);
    }
    return;
}
int query(int u,int v,int k)
{
    int ans=0;
    while(u!=v){
        if(dep[v]>dep[u]) swap(u,v);
        int tmp=G[fa[u]].size()<m?w[u]:__gcd(a[fa[u]],a[u]);
        ans+=tmp<=k;
        u=fa[u];
    }
    return ans;
}
int main()
{
    int n,q,u,v,op,k,x;
    scanf("%d%d",&n,&q);
    m=sqrt(n);
    for(int i=1;i<=n;++i) scanf("%d",a+i);
    for(int i=1;i<n;++i){
        scanf("%d%d",&u,&v);
        G[u].emplace_back(v);
        G[v].emplace_back(u);
    }
    dfs(1);
    while(q--){
        scanf("%d%d",&op,&u);
        if(op==1){
            scanf("%d",&x);
            if(a[u]==x) continue;
            a[u]=x;
            w[u]=__gcd(a[fa[u]],x);
            if(G[u].size()>=m) continue;
            for(int v:G[u]){
                if(v==fa[u]) continue;
                w[v]=__gcd(a[v],x);
            }
        }
        else{
            scanf("%d%d",&v,&k);
            printf("%d\n",query(u,v,k));
        }
    }
    return 0;
}

C++11(clang++ 3.9) 解法, 执行用时: 1141ms, 内存消耗: 2404K, 提交时间: 2020-05-15 19:29:21

#include<bits/stdc++.h>
using namespace std;
const int N=40005;
int ne[N],fa[N],in[N],tot,out[N],fi[N],zz[N],n,m,a[N],x,y,opt,z,vis[N];
int pd(int x,int y){
	return in[x]<=in[y]&&out[x]>=out[y];
}
void dfs(int x,int y){
	fa[x]=y;in[x]=++tot;
	for (int i=fi[x];i;i=ne[i])
		if (zz[i]!=y)dfs(zz[i],x);
	out[x]=++tot;
}
void jb(int x,int y){
	ne[++tot]=fi[x];
	fi[x]=tot;
	zz[tot]=y;
}
int main(){
	scanf("%d%d",&n,&m);
	for (int i=1;i<=n;i++)scanf("%d",&a[i]);
	for (int i=1;i<n;i++){
		scanf("%d%d",&x,&y);
		jb(x,y);jb(y,x);
	}
	tot=1;
	dfs(1,0);
	while (m--){
		scanf("%d",&opt);
		if (opt==1){
			scanf("%d",&x);
			scanf("%d",&a[x]);
			for (int i=fi[x];i;i=ne[i])
				if (zz[i]!=fa[x])vis[zz[i]]=0;
			vis[x]=0;
		}
		else {
			scanf("%d%d%d",&x,&y,&z);
			int ans=0;
			while (!pd(x,y)){
				if (!vis[x])vis[x]=__gcd(a[x],a[fa[x]]);
				ans+=vis[x]<=z;
				x=fa[x];
			}
			swap(x,y);
			while (x!=y){
				if (!vis[x])vis[x]=__gcd(a[x],a[fa[x]]);
				ans+=vis[x]<=z;
				x=fa[x];
			}
			printf("%d\n",ans);
		}
	}
	return 0;
}

上一题