bnu 51636 Squared Permutation(樹狀陣列)(北師16校賽)
最近,無聊的過河船同學在玩一種奇怪的名為“小Q的惡作劇”的紙牌遊戲。
現在過河船同學手有張牌,分別寫著,打亂順序之後排成一行,位置從左往右按照標號。
接下來小Q同學會給出個操作,分為以下兩種:
1.給定,交換從左往右數的第和第張牌,
2.給定,對從左往右數的第張牌,記下位置是這張牌上的數字的牌的數字,詢問所有記下的數字加起來的結果。
雖然無聊的過河船同學精通四則運算,但是要完成這麼大的計算量還是太辛苦了,希望你能幫他處理這些操作。
Input
第一行是一個正整數,表示測試資料的組數,
對於每組測試資料,
第一行是一個整數,
第二行包含一個的排列,其中第個數表示第張牌上的數字,
第三行是一個整數
接下來行,每行包含三個整數,其中表示操作的型別。
Output
對於每組測試資料,依次輸出所有查詢操作的結果,每個結果一行。
Sample Input
1 3 1 2 3 3 2 1 2 1 1 3 2 2 3
Sample Output
3 5
Hint
對於樣例,
第二次操作後牌上的數字從左往右依次是3,2,1,
第三次操作的結果是位置是第2張牌上的數字的牌的數字加上位置是第3張牌上的數字的牌的數字,也就是第2張牌上的數字加上第1張牌上的數字,結果是5。
Source
Author
quailty題目大意:
有一個1到n的排列組成的的數列ai,有m次詢問,詢問有兩種操作,1.交換a[l],a[r],2.求以a[l]...到a[r]這些數為下標的a中數的和。
解題思路:
樹狀陣列i的位置維護以a[i]為下標a中的數(即a[a[i]]),這樣一來就是每次2詢問求和都是連續的區間,那麼在1詢問的時候就更新樹狀陣列:
第一步:把a中的數當作指向自己陣列中數的指標,更新指向l,r的數字在樹狀陣列中的值(如果指向lr本身就指向l或者r那就不需要改,以免和下面重複)
第二步:把a[l],a[r]交換之後更新樹狀陣列中的l和r為新的a[a[l]],a[a[r]].
2詢問的時候直接輸出sum[l]-sum[i-1]即可,因為之前定義樹狀陣列的意義的時候已經可以保證這樣一點
#include <iostream>
#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<string>
#include<vector>
#include<stack>
#include<queue>
#include<set>
#include<map>
#define C(a) memset(a,0,sizeof a)
#define C_1(a) memset(a,-1,sizeof a)
#define C_I(a) memset(a,0x3f,sizeof a)
typedef long long ll;
using namespace std;
const int maxn = 1e6 + 20;
ll a[maxn], n, bit[maxn];
void add(int x, int y)
{
while (x <= n)
{
a[x] += y;
x += x&-x;
}
}
ll sum(int x)
{
ll s = 0;
while (x > 0)
{
s += a[x];
x -= x&-x;
}
return s;
}
void init()
{
C(a);
C(bit);
}
int num[maxn];
int ma[maxn];
int main()
{
int T; cin >> T;
while (T--)
{
scanf("%lld", &n);
init();
for (int i = 1; i <= n; i++)
{
scanf("%d", &num[i]);
ma[num[i]] = i;
}
for (int i = 1; i <= n; i++)
{
bit[i] = num[num[i]];
add(i, num[num[i]]);
}
int q;
scanf("%d", &q);
int type, r, l;
while (q--)
{
scanf("%d%d%d", &type, &l, &r);
if (type == 1)
{
if (ma[l] != l&&ma[l] != r)
{
add(ma[l], -num[l]);
add(ma[l], num[r]);
}
if (ma[r] != r&&ma[r] != l)
{
add(ma[r], -num[r]);
add(ma[r], num[l]);
}
add(r, -num[num[r]]);
add(l, -num[num[l]]);
swap(num[l], num[r]);
add(l, num[num[l]]);
add(r, num[num[r]]);
ma[num[r]] = r;
ma[num[l]] = l;
}
else
{
printf("%lld\n", sum(r) - sum(l - 1));
}
}
}
return 0;
}