您的位置:首页 > 其它

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

2017-05-04 20:41 435 查看
原文地址:http://www.cnblogs.com/GXZlegend/p/6809714.html

题目描述



输入



输出

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

样例输入

4

1 100 5 5

5

1 1 2

2 1 2

1 1 2

2 2 3

1 1 4

样例输出

101

11

11

题解

并查集+树状数组,附带一点数学知识

因为√1=1,且一个数x开接近log2(log2x)次平方后就会变成1,这个数是非常小的。

所以我们完全可以暴力修改,只需要知道每次的修改区间中有多少真正需要修改的数即可。

这可以用并查集来维护,b[i]表示i之后(包括i)第一个点权不为1的数的位置,当然还需要一个find函数。

这样暴力修改,但是不能暴力求和,还需要用一个树状数组来维护区间和。

注意开long long,并且把b[n+1]赋为n+1以防止越界。

#include <cstdio>
#include <cmath>
#include <algorithm>
#define N 100010
using namespace std;
typedef long long ll;
int n , b
;
ll w
, f
;
int find(int x)
{
return b[x] == x ? x : b[x] = find(b[x]);
}
void update(int x , ll a)
{
int i;
for(i = x ; i <= n ; i += i & -i) f[i] += a;
}
ll query(int x)
{
int i;
ll ans = 0;
for(i = x ; i ; i -= i & -i) ans += f[i];
return ans;
}
int main()
{
int m , i , opt , l , r;
ll tmp;
scanf("%d" , &n);
for(i = 1 ; i <= n ; i ++ )
scanf("%lld" , &w[i]) , b[i] = (w[i] <= 1 ? i + 1 : i) , update(i , w[i]);
b[n + 1] = n + 1;
scanf("%d" , &m);
while(m -- )
{
scanf("%d%d%d" , &opt , &l , &r);
if(opt == 1) printf("%lld\n" , query(r) - query(l - 1));
else
{
for(i = find(l) ; i <= r ; i = find(i + 1))
{
tmp = (ll)sqrt(w[i]) , update(i , tmp - w[i]) , w[i] = tmp;
if(w[i] <= 1) b[i] = find(i + 1);
}
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: