题目链接:https://www.bnuoj.com/v3/problem_show.php?pid=51636
第i个数在线段树中存放的是第i个数作为位置的数字,两数交换的时候会影响区间和,画一棵线段树会发现会有四个点影响这个区间和。
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 #define lrt rt << 1 5 #define rrt rt << 1 | 1 6 typedef long long LL; 7 8 const int maxn = 100100; 9 const int maxm = maxn << 3; 10 int n, q; 11 int a[maxn], p[maxn]; 12 LL seg[maxm]; 13 14 void pushup(int rt) { 15 seg[rt] = seg[lrt] + seg[rrt]; 16 } 17 18 void build(int rt, int l, int r) { 19 if(l == r) { 20 seg[rt] = a[a[l]]; 21 return; 22 } 23 seg[rt] = 0; 24 int m = (l + r) >> 1; 25 build(lrt, l, m); 26 build(rrt, m+1, r); 27 pushup(rt); 28 } 29 30 void update(int rt, int l, int r, int pos, int val) { 31 if(l == r) { 32 seg[rt] = val; 33 return; 34 } 35 int m = (l + r) >> 1; 36 if(pos <= m) update(lrt, l, m, pos, val); 37 if(pos > m) update(rrt, m+1, r, pos, val); 38 pushup(rt); 39 } 40 41 LL query(int rt, int L, int R, int l, int r) { 42 if(l >= L && R >= r) return seg[rt]; 43 int m = (l + r) >> 1; 44 LL ret = 0; 45 if(m >= L) ret += query(lrt, L, R, l, m); 46 if(m < R) ret += query(rrt, L, R, m+1, r); 47 return ret; 48 } 49 50 int main() { 51 // freopen("in", "r", stdin); 52 int T, o, l, r; 53 scanf("%d", &T); 54 while(T--) { 55 scanf("%d", &n); 56 for(int i = 1; i <= n; i++) { 57 scanf("%d", &a[i]); 58 p[a[i]] = i; 59 } 60 build(1, 1, n); 61 scanf("%d", &q); 62 while(q--) { 63 scanf("%d%d%d", &o, &l, &r); 64 if(o == 2) printf("%lld ", query(1, l, r, 1, n)); 65 else { 66 swap(a[l], a[r]); 67 swap(p[a[l]], p[a[r]]); 68 update(1, 1, n, l, a[a[l]]); 69 update(1, 1, n, r, a[a[r]]); 70 update(1, 1, n, p[l], a[l]); 71 update(1, 1, n, p[r], a[r]); 72 } 73 } 74 } 75 return 0; 76 }