zoukankan      html  css  js  c++  java
  • CSUSTOJ 4000-你真的会数据结构吗?(状压+素数分解)

    题目链接:http://acm.csust.edu.cn/problem/4000
    CSDN食用链接:https://blog.csdn.net/qq_43906000/article/details/108023439

    Description

    现在给你一棵有n个结点的有根树,根为结点1,每个结点有点权(a_i)

    现有q次询问:

    (type 1: 1 u x)表示将uu结点的点权修改为x;

    (type 2: 2 u)表示询问从结点uu的儿子结点中挑选出尽可能多的儿子结点(至少要选一个)使得(f(n))最小,其中n为所挑选出的结点的权值之积,函数(f(n))为d的个数,其中d满足(dmid n)(即d整除n)且(gcd(d,frac{n}{d})=1)。注意若u为叶子结点则输出0 0。

    Input
    第一行包含一个正整数(n(5leq nleq 1e5)),表示结点个数。

    接下来(n-1)行每行两个正整数u v,表示u和v之间有一条边,注意u不一定是v的父亲结点。

    (n+1)行包含n个正整数(a_i(1leq a_ileq 30)),表示结点ii的权值。

    (n+2)行包含一个正整数(q(1leq qleq 1e5)),表示询问次数。

    接下来q行,每行第一个数为(op(op=1 or 2))

    (op=1),则该行还有两个正整数(u x(1leq uleq n,1leq xleq 30)));

    (op=2),则该行还有一个正整数(u(1leq uleq n))

    Output
    对于每一个(type2)输出挑选的子结点个数及f(n)f(n)的值,用空格隔开,数据保证至少有一次type2。

    Sample Input 1
    7
    1 2
    1 3
    2 4
    2 5
    3 6
    3 7
    2 3 4 5 6 7 8
    3
    2 2
    1 2 1
    2 1

    Sample Output 1
    1 2
    1 1

    此题用线段树来写的话稍微有点恶心心。。。。我们可以先想想暴力的方法。

    我们先观察它要求什么,对于一个数,它一定可以分解为(s=p_1^{k_1} imes p_2^{k_2} imes cdots imes p_n^{k_n}),那么如果要选一个数使得d,使得d是s的因子,而且(gcd(d,frac{n}{d})=1),那么只能选择(p_i^{k_i}),也就是说我们只需要求出n有几个素因子就好了,然后我们直接枚举是否选择该素因子,那么也就会得到(2^i)个d,其中(i)表示的是该数的素因子个数。

    那么对于每一个数就可以用一个二进制状态来表示它的素因子状态,比如说(4=1,8=1,3=10,6=11),然后我们对每个点记录其儿子节点的每个状态的数量:

    void dfs(int u,int fa)
    {
    	father[u]=fa;
    	for (auto v:g[u]){
    		if (v==fa) continue;
    		dfs(v,u);
    		vis[u][stk[a[v]]]++;//记录其儿子该状态数量
    	}
    }
    

    接下来修改的时候我们直接对vis进行修改就好了,直接该点父节点的将原来的该儿子的状态-1,现状态+1:

    vis[father[u]][stk[a[u]]]--;
    vis[father[u]][stk[x]]++;
    a[u]=x;
    

    接下来就是询问操作了,由于状态的数量只有30个,所以我们可以直接对每一个状态进行查询其个数和其可以选择的d的个数,即:

    for (int i=1; i<=30; i++) {
    	if (vis[u][stk[i]]) {
    		if (selct[stk[i]]<ans2) {
    			ans2=selct[stk[i]];
    			ans1=vis[u][stk[i]];
    		}
    		else if (selct[stk[i]]==ans2) ans1=max(ans1,vis[u][stk[i]]);
    	}
    }
    

    以下是AC代码:

    #include <bits/stdc++.h>
    using namespace std;
    
    const int mac=1e5+10;
    const int inf=1e9+10;
    
    int a[mac];
    vector<int>g[mac];
    int prim[50],selct[1<<11],father[mac];
    int stk[50];
    unordered_map<int,int>vis[mac];
    
    void dfs(int u,int fa)
    {
    	father[u]=fa;
    	for (auto v:g[u]){
    		if (v==fa) continue;
    		dfs(v,u);
    		vis[u][stk[a[v]]]++;
    	}
    }
    
    int main(int argc, char const *argv[])
    {
    	int n,q;
    	scanf ("%d",&n);
    	for (int i=1; i<n; i++){
    		int u,v;
    		scanf ("%d%d",&u,&v);
    		g[u].push_back(v); g[v].push_back(u);
    	}
    	for (int i=1; i<=n; i++) scanf ("%d",&a[i]);
    	
    	int cnt=0;
    	for (int i=2; i<=30; i++){
    		int mk=0;
    		for (int j=2; j<=sqrt(i); j++)
    			if (i%j==0) {mk=1; break;}
    		if (!mk) prim[cnt++]=i;
    	}
    
    	for (int i=0; i<=30; i++){
    		int nb=0;
    		for (int j=0; j<cnt; j++){
    			if (i%prim[j]==0) nb++,stk[i]|=1<<j;
    		}
    		selct[stk[i]]=1<<nb;
    	}
    
    	dfs(1,0);
    	scanf ("%d",&q);
    	while (q--){
    		int opt,u,x;
    		scanf ("%d%d",&opt,&u);
    		if (opt==1){
    			scanf ("%d",&x);
    			vis[father[u]][stk[a[u]]]--;
    			vis[father[u]][stk[x]]++;
    			a[u]=x;
    		}
    		else {
    			if (u!=1 && g[u].size()==1) {printf("0 0
    "); continue;}
    			int ans1=0,ans2=inf;
    			for (int i=1; i<=30; i++){
    				if (vis[u][stk[i]]){
    					if (selct[stk[i]]<ans2){
    						ans2=selct[stk[i]];
    						ans1=vis[u][stk[i]];
    					}
    					else if (selct[stk[i]]==ans2) ans1=max(ans1,vis[u][stk[i]]);
    				}
    			}
    			printf ("%d %d
    ",ans1,ans2);
    		}
    	}
    	return 0;
    }
    

    暴力写完之后也可以写下线段树的写法。。。只不过有点恶心,首先你需要跑一下bfs序来找到每个点的儿子节点的连续编号,然后将所有的数丢到线段树里面,然后就是和暴力一样地跑了。。。将每个儿子的每个状态转移到父节点,然后区间询问一下就好了

  • 相关阅读:
    Android实战——第三方服务之Bmob后端云的集成、用户登陆、用户注册、获取用户、用户注销(一)
    Android实战——第三方服务之Bmob后端云的答题系统小项目(四)
    10.Python运行Scrapy时出现错误: ModuleNotFoundError: No module named 'win32api'
    基础小知识(1)
    9.Python安装scrapy教程
    1.使用Fiddler进行接口测试
    8.Python编写登录接口
    18.Selenium+Python案例 -- 豆瓣
    17.Selenium+Python日期控件小案例
    16.Selenium+Python关于句柄的小Demo
  • 原文地址:https://www.cnblogs.com/lonely-wind-/p/13509092.html
Copyright © 2011-2022 走看看