# BZOJ 3211 花神游历各国

1.因为每个数字在1e9以内那么开平方到1，次数小于10的，所以想要每次开方跳过为1的数，现在就将操作改为单点修改，复杂度也满足。

2.现在的问题是单点修改，询问区间和了，树状数组就可以解决~\(≧▽≦)/~

3.但是怎么才能每次开方跳过1呢？并查集可以维护，如果一个数开方以后等于1了，就将它连向它后面那个不为1的数，实现删除操作，具体见代码~

/**************************************************************
Problem: 3211
User: Xgtao
Language: C++
Result: Accepted
Time:1140 ms
Memory:5908 kb
****************************************************************/

#include <cstdio>
#include <cmath>
#include <iostream>
using namespace std;

#define lowbit(i) i&-i
#define ll long long
const int N = 1e5 + 7;
int pa[N], n, m, o, L, R, x[N];
ll S[N];

int K = 0;
char c = getchar ();
while (c < '0' || c > '9') c = getchar ();
while (c >= '0' && c <= '9') K = K * 10 + c - '0', c = getchar ();
return K;
}

int find (int x) {
return pa[x] == x ? x : pa[x] = find (pa[x]);
}

void update (int x, int w) {
for (int i = x; i < N; i += lowbit (i)) S[i] += w;
}

ll sum (int x) {
ll ret = 0;
for (int i = x; i >= 1; i -= lowbit (i)) ret += S[i];
return ret;
}

int main () {
for (int i = 1; i <= n + 1; ++i) pa[i] = i;
for (int i = 1; i <= n; ++i) {
if (x[i] == 1 || x[i] == 0) pa[i] = find (i + 1);
update (i, x[i]);
}
while (m--) {
if (o == 1) printf ("%lld\n", sum (R) - sum (L - 1));
else if (o == 2) {
for (int i = find (L); i <= R; i = find (i + 1)) {
update (i, (int)sqrt (x[i]) - x[i]);
x[i] = sqrt (x[i]);
if (x[i] == 1) pa[i] = find (i + 1);
}
}
}
return 0;
}

posted @ 2016-10-17 08:51  xgtao  阅读(161)  评论(0编辑  收藏  举报