【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
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
11
11
【分析】
开始看一眼觉得线段树可做。
后来看题解用树状数组瞬秒......orzzz,注意到任何一个int都可以在很小的次数下变为1,所以直接暴力单点修改,将变成1的数parent设为它右边的数。
注意,输入中可能会有很多的0....直接写优化不好会T。
1 #include <iostream> 2 #include <cstdio> 3 #include <algorithm> 4 #include <cstring> 5 #include <vector> 6 #include <utility> 7 #include <iomanip> 8 #include <string> 9 #include <cmath> 10 #include <queue> 11 #include <map> 12 13 const int MAXN = 100000 + 10; 14 const int MAX = 30000 + 10; 15 using namespace std; 16 typedef long long ll; 17 int n; 18 ll C[MAXN]; 19 int data[MAXN], parent[MAXN]; 20 21 int SQRT(int x){return (int)floor(sqrt((double)x * 1.0));} 22 int lowbit(int x){return x & -x;} 23 void add(int x, int val){ 24 while (x <= n){ 25 C[x] += val; 26 x += lowbit(x); 27 } 28 return; 29 } 30 ll sum(int x){ 31 ll cnt = 0; 32 while (x > 0){ 33 cnt += C[x]; 34 x -= lowbit(x); 35 } 36 return cnt; 37 } 38 int find(int x) {return parent[x] == x? x : parent[x] = find(parent[x]);} 39 void init(){ 40 memset(C, 0, sizeof(C)); 41 scanf("%d", &n); 42 for (int i = 1; i <= n; i++){ 43 scanf("%d", &data[i]); 44 add(i, data[i]); 45 parent[i] = i; 46 if (data[i] == 1 || data[i] == 0) parent[i] = i + 1; 47 } 48 parent[n + 1] = n + 1; 49 } 50 void work(){ 51 int q; 52 scanf("%d", &q); 53 for (int i = 1; i <= q; i++){ 54 int t, x, y; 55 scanf("%d%d%d", &t, &x, &y); 56 if (t == 1) printf("%lld\n", sum(y) - sum(x - 1)); 57 else{ 58 for (int i = x; i <= y; i = find(i + 1)){ 59 int tmp = data[i]; 60 data[i] = SQRT(data[i]); 61 add(i, data[i] - tmp); 62 if (data[i] <= 1) parent[i] = find(i + 1); 63 } 64 } 65 } 66 } 67 68 int main(){ 69 int T; 70 #ifdef LOCAL 71 freopen("data.txt", "r", stdin); 72 freopen("out.txt", "w", stdout); 73 #endif 74 init(); 75 work(); 76 return 0; 77 }