BZOJ 3211: 花神游历各国 |树状数组|并查集

树状数组维护前缀和

并查集维护从一个点向后(包括这个点)第一个权值>1的点

因为权值<=1更新是没有必要的

而开根号一个int的数顶多开5次就成了1

复杂度是nlogn的

#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<queue>
#include<vector>
#include<set>
#include<map>
#include<iostream>
#include<algorithm>
#define lowbit(x) x&(-x)
#define T 100010
using namespace std;
int sc()
{
	int i=0,f=1;char c=getchar();
	while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();}
	while(c>='0'&&c<='9')i=i*10+c-'0',c=getchar();
	return i*f;
}
long long tr[T];
int nxt[T],a[T];
int n,m;
int find(int x){return nxt[x]==x?x:nxt[x]=find(nxt[x]);}
void change(int x,int f){ for(;x<=n;x+=lowbit(x))tr[x]+=f; }
void solve(int l,int r)
{
	for(int i=find(nxt[l]);i<=r;i=find(nxt[i+1]))
	{
		int x=(int)sqrt(a[i]);
		change(i,x-a[i]);
		a[i]=x;
		if(a[i]<=1)nxt[i]=find(nxt[i+1]);
	}
}
long long ask(int x)
{
	long long ans=0;
	for(;x;x-=lowbit(x)) ans+=tr[x];
	return ans;
}
int main()
{
	n=sc();
	for(int i=1;i<=n;i++)a[i]=sc(),change(i,a[i]);
	for(int i=1;i<=n;i++)nxt[i]=i;nxt[n+1]=n+1;
	m=sc();
	for(int i=1;i<=m;i++)
	{
		int x=sc(),a=sc(),b=sc();
		if(x==2) solve(a,b);
		else     printf("%lld\n",ask(b)-ask(a-1));
	}
	return 0;
}
	


你可能感兴趣的:(并查集,树状数组)