【BZOJ3211】花神游历各国 并查集+树状数组

【BZOJ3211】花神游历各国

Description

 

Input

 

Output

每次x=1时,每行一个整数,表示这次旅行的开心度

Sample Input

4
1 100 5 5
5
1 1 2
2 1 2
1 1 2
2 2 3
1 1 4

Sample Output

101
11
11

题解:网上好多题解说线段树,感觉树状数组+并查集就可以啊!

易知一个数只要开log(log(n))次平方就会变成1或0,所以我们用并查集维护没有变成1或0的点,修改的时候暴力修改那些没有变成1或0的点,用树状数组更新前缀和,查询的时候直接上树状数组,这样复杂度是O(nlogn*log(log(n)))的

注意!并查集的f[i]指向的是i下一个没有变成1或0的点,所以别忘了f[n+1]=n+1!!!(WA的教训)

#include <cstdio>
#include <cstring>
#include <iostream>
#include <cmath>
using namespace std;
const int maxn=100010;
typedef long long ll;
int n,m;
int f[maxn];
ll v[maxn],s[maxn];
int find(int x)
{
	return (f[x]==x)?x:(f[x]=find(f[x]));
}
void updata(int x,ll val)
{
	for(int i=x;i<=n;i+=i&-i)	s[i]+=val;
}
ll query(int x)
{
	int i;
	ll ret=0;
	for(i=x;i;i-=i&-i)	ret+=s[i];
	return ret;
}
int main()
{
	scanf("%d",&n);
	int i,j,a,b,c;
	for(i=1;i<=n;i++)	scanf("%lld",&v[i]),updata(i,v[i]),f[i]=i;
	f[n+1]=n+1;
	scanf("%d",&m);
	for(i=1;i<=m;i++)
	{
		scanf("%d%d%d",&c,&a,&b);
		if(a>b)	swap(a,b);
		if(c==1)
		{
			printf("%lld\n",query(b)-query(a-1));
			continue;
		}
		for(j=find(a);j<=b;j=find(j+1))
		{
			updata(j,-v[j]),v[j]=(ll)sqrt(1.0*v[j]),updata(j,v[j]);
			if(v[j]==1)	f[j]=find(j+1);
		}
	}
	return 0;
}

嘿嘿嘿我long long写错了你们看不见,略略略~

同上帝造题的7分钟2,但是说好的双倍经验呢?我那道题long long写错就拿不到分了~QAQ

posted @ 2017-05-05 07:41  CQzhangyu  阅读(466)  评论(0编辑  收藏  举报