BZOJ3211&&洛谷P4145 上帝造題的七分鐘2/花神遊歷各國

思維題

樹狀數組+並查集維護

思路

發現最大數101210^{12}開根號最大也就開1012>106>103>31>5>2>110^{12}->10^{6}->10^3->31->5->2->1,所以我們每次開根號暴力修改,一個數最多也就被暴力修改6次就不會變了,然後我們就可以跳過這個數了,所以我們需要一個可以把它和他下一個連起來的東西,所以我們用了並查集,每次把一個數改成1之後,就把他和他下一個連起來,然後在樹狀數組上更新就好了

代碼

//By AcerMo
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define lowbit(x) x&(-x)
#define lli long long int
using namespace std;
const int M=200500;
int fa[M];
lli a[M],s[M],n,m;
inline void read(lli &x)
{
	x=0;char ch=getchar();
	while (!isdigit(ch)) ch=getchar();
	while (isdigit(ch)) x=x*10+ch-'0',ch=getchar();
	return ;
}
inline void write(lli x)
{
	if (x>9) write(x/10);
	putchar(x%10+'0');
	return ;
}
inline int find(int x)
{
	if (x==fa[x]) return x;
	return fa[x]=find(fa[x]);
}
inline void add(int p,lli x)
{
	for (int i=p;i<=n;i+=lowbit(i)) s[i]+=x;
	return ;
}
inline lli sum(int p)
{
	lli su=0;
	for (int i=p;i;i-=lowbit(i)) su+=s[i];
	return su;
}
signed main()
{
	read(n);
	for (int i=1;i<=n;i++) 
	read(a[i]),add(i,a[i]),fa[i]=(a[i]==1?i+1:i);
	read(m);fa[n+1]=n+1;
	while (m--)
	{
		lli fl,x,y;
		read(fl);read(x);read(y);
		if (x>y) swap(x,y);
		if (fl==1) write(sum(y)-sum(x-1)),puts("");
		else 
		for (int i=x;i<=y;)
		{
			int t=sqrt(a[i]);
			add(i,t-a[i]);a[i]=t;
			fa[i]=(a[i]<=1)?i+1:i;
			i=(find(i)==i?i+1:fa[i]); 
		}
	}
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章