• [HDU 5634] Rikka with Phi


    维护一个数据结构,支持区间覆盖,区间取phi,区间查询和。
    区间取phi,理论分析,对于一个偶数取phi变为原来的一半,奇数取phi变为偶数。所以最多log次,就可以将一个数变成1。而phi(1)=1,所以可以通过维护区间最大值,若一段区间最大值已经是1,那么就不必修改了,这个时候时间复杂度为(O(log^2n))
    而两个操作结合起来,就有点麻烦,因为覆盖之后不好取phi,所以需要引入一个标记,记录一个区间所有值是否相等,这样的话一次覆盖最多遍历log个区间,修改复杂度也得到了保证。

    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #include<cstdlib>
    #include<vector>
    #include<set>
    #include<map>
    #include<string>
    #include<iostream>
    #include<queue>
    #include<cctype>
    using namespace std;
    
    #define A(x) cout << #x << " " << x << endl;
    #define AA(x,y) cout << #x << " " << x << #y << " " << y << endl;
    #define B cout << "Break" << endl;
    #define ll long long
    #define inf 1000000000
    
    int read()
    {
    	int c = getchar();
    	int x = 0,f = 1;
    	while(!isdigit(c))
    	{
    		if(c == '-') f = -1;
    		c = getchar();
    	}
    	while(isdigit(c))
    	{
    		x = x * 10 + c - '0';
    		c = getchar();
    	}
    	return f * x;
    }
    #define N 300010
    int sum[N << 2],lazy[N << 2],mx[N << 2],tag[N << 2],seq[N];
    #define MAX 10000010
    int pr[MAX],pn,phi[MAX],vis[MAX];
    int n,m;
    void sieve()
    {
    	phi[1] = 1;
    	for(int i = 2;i <= MAX - 10;++i)
    	{
    		if(!vis[i])
    		{
    			phi[i] = i - 1;
    			pr[++pn] = i;
    		}
    		for(int j = 1;j <= pn && i * pr[j] <= MAX - 10;++i)
    		{
    			vis[i * pr[j]] = 1;
    			if(i % pr[j] == 0)
    			{
    				phi[i * pr[j]] = phi[i] * pr[j];
    				break;
    			}
    			phi[i * pr[j]] = phi[i] * phi[pr[j]];
    		}
    	}
    }
    #define mid (l + r >> 1)
    #define ls x << 1,l,mid
    #define rs x << 1 | 1,mid + 1,r
    void push_up(int x)
    {
    	sum[x] = sum[x << 1] + sum[x << 1 | 1];
    	mx[x] = max(mx[x << 1],mx[x << 1 | 1]);
    	tag[x] = (tag[x << 1] && tag[x << 1 | 1] && mx[x << 1] == mx[x << 1 | 1]);
    	return;
    }
    void build(int x,int l,int r)
    {
    	sum[x] = mx[x] = tag[x] = lazy[x] = 0;
    	if(l == r)
    	{
    		sum[x] = mx[x] = seq[l];
    		tag[x] = 1;
    		return;
    	}
    	build(ls);
    	build(rs);
    	push_up(x);
    }
    void add(int x,int l,int r,int k)
    {
    	lazy[x] = mx[x] = k;
    	tag[x] = 1;
    	sum[x] = (r - l + 1) * k;
    	return;
    }
    void push_down(int x,int l,int r)
    {
    	if(!lazy[x]) return;
    	add(ls,lazy[x]);
    	add(rs,lazy[x]);
    	lazy[x] = 0;
    	return;
    }
    void to_phi(int x,int l,int r,int p,int q)
    {
    	if(mx[x] <= 1) return;
    	if(p <= l && r <= q && tag[x])
    	{
    		lazy[x] = mx[x] = phi[mx[x]];
    		sum[x] = (r - l + 1) * mx[x];
    		return;
    	}
    	push_down(x,l,r);
    	if(p <= mid) to_phi(ls,p,q);
    	if(q > mid) to_phi(rs,p,q);
    	push_up(x);
    	return;
    }
    void modify(int x,int l,int r,int p,int q,int k)
    {
    	if(p <= l && r <= q)
    	{
    		tag[x] = 1;
    		lazy[x] = mx[x] = k;
    		sum[x] = (r - l + 1) * k;
    		return;
    	}
    	push_down(x,l,r);
    	if(p <= mid) modify(ls,p,q,k);
    	if(q > mid) modify(rs,p,q,k);
    	push_up(x);
    	return;
    }
    int query(int x,int l,int r,int p,int q)
    {
    	if(p <= l && r <= q) return sum[x];
    	int ret = 0;
    	push_down(x,l,r);
    	if(p <= mid) ret += query(ls,p,q);
    	if(q > mid) ret += query(rs,p,q);
    	return ret;
    }
    int main()
    {
    	sieve();
    	int T = read();
    	while(T--)
    	{
    		int n = read(),m = read();
    		for(int i = 1;i <= n;++i) seq[i] = read();
    		build(1,1,n);
    		while(m--)
    		{
    			int op = read(),l = read(),r = read();
    			if(op == 1) to_phi(1,1,n,l,r);
    			if(op == 2)
    			{
    				int k = read();
    				modify(1,1,n,l,r,k);
    			}
    			if(op == 3) printf("%d
    ",query(1,1,n,l,r));
    		}
    
    	}
    }
    
  • 相关阅读:
    “北漂”的那些年 5
    “北漂”的那些年 4
    全国省市区代码-2020版
    记一次CDH修改IP
    Python爬取抖音视频
    代码生成,减少70%的重复劳动
    Log4J配置详解
    linux常用命令
    tomcat修改默认访问首页
    java根据身份证号和获取用户年龄和性别的工具类
  • 原文地址:https://www.cnblogs.com/lijilai-oi/p/12409521.html
Copyright © 2020-2023  润新知