F. SUM and REPLACE(线段树&dsu)

Posted Harris-H

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了F. SUM and REPLACE(线段树&dsu)相关的知识,希望对你有一定的参考价值。

F. SUM and REPLACE(线段树&dsu)

与区间开平方是一个题型,区间变成 d ( i ) d(i) d(i) 最多变 6 6 6次。

可以线段树维护区间和和区间最大值,当区间最大值 ≤ 2 \\le 2 2直接返回不修改。

然后就是裸的线段树。

线段树代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long
int n,m,i,j,k,t[1200005],a[300005],d[1000005];
ll s[1200005];
void up(int R)
{
	s[R]=s[R<<1]+s[R<<1|1];
	t[R]=max(t[R<<1],t[R<<1|1]);
}
void build(int R,int l,int r)
{
	if(l==r)
	{
		s[R]=t[R]=a[l];
		return;
	}
	int mid=l+r>>1;
	build(R<<1,l,mid);
	build(R<<1|1,mid+1,r);
	up(R);
}
ll ask(int R,int l,int r,int l1,int r1)
{
	if(l1<=l&&r<=r1)return s[R];
	int mid=l+r>>1;
	ll s=0;
	if(l1<=mid)s+=ask(R<<1,l,mid,l1,r1);
	if(r1>mid)s+=ask(R<<1|1,mid+1,r,l1,r1);
	return s;
}
void fix(int R,int l,int r,int l1,int r1)
{
	if(t[R]<3)return;
	if(l==r)
	{
		s[R]=t[R]=d[t[R]];
		return;
	}
	int mid=l+r>>1;
	if(l1<=mid)fix(R<<1,l,mid,l1,r1);
	if(r1>mid)fix(R<<1|1,mid+1,r,l1,r1);
	up(R);
}
int main()
{
	for(i=1;i<=1000000;i++)for(j=i;j<=1000000;j+=i)d[j]++;
	scanf("%d%d",&n,&m);
	for(i=1;i<=n;i++)scanf("%d",a+i);
	build(1,1,n);
	while(m--)
	{
		scanf("%d%d%d",&i,&j,&k);
		if(i==1)fix(1,1,n,j,k);
		else cout<<ask(1,1,n,j,k)<<endl;
	}
	return 0;
}

此题还有个解法:利用并查集,每个结点向右连第一个大于 d ( i ) > 2 d(i)>2 d(i)>2的位置。

每次就一边更新区间,一遍修改 d s u dsu dsu即可,直接区间求和,上线段树或者BIT都可。

d s u dsu dsu代码

#include<cstdio>
const int N=1000006;
int n,m,i,j,k,a[N],d[N],f[N],opt,l,r;
long long c[N],s;
int p(int x){
	return x==f[x]?x:f[x]=p(f[x]);
}
void add(int x,int y){
	while(y<=n)
		c[y]+=x,y+=y&-y;
}
long long sum(int x){
	for(s=0;x;x-=x&-x)
		s+=c[x];
	return s;
}
int main(){
	for(i=1;i<N;i++)
		for(j=i;j<N;j+=i)
			d[j]++;
	scanf("%d%d",&n,&m);
	for(i=1;i<=n;i++){
		scanf("%d",a+i);
		add(a[i],i);
		if(a[i]>2)
			f[i]=i;
		else
			f[i]=i+1;
	}
	f[i]=i;
	while(m--){
		scanf("%d%d%d",&opt,&l,&r);
		if(opt==1){
			while((l=p(l))<=r){
				add(-a[l],l);
				a[l]=d[a[l]];
				add(a[l],l);
				if(a[l]<=2)
					f[l]=l+1;
				l++;
			}
		}
		else
			printf("%lld\\n",sum(r)-sum(l-1));
	}
}

以上是关于F. SUM and REPLACE(线段树&dsu)的主要内容,如果未能解决你的问题,请参考以下文章

CodeForces - 920F SUM and REPLACE (线段树)

codeforces CF920F SUM and REPLACE 线段树 线性筛约数

Educational Codeforces Round 37-F.SUM and REPLACE (线段树,线性筛,收敛函数)

Educational Codeforces Round 37F. SUM and REPLACE 线段树+线性筛

CF920F SUM and REPLACE 题解

Codeforces Round #638 (Div. 2) F. Phoenix and Memory 区间贪心+线段树