Squared Permutation
最近,无聊的过河船同学在玩一种奇怪的名为“小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
题解:
明显的线段树
不过要注意的是在交换的的时候,可能影响的位置有4个,多更新就好了
#include <iostream> #include <cstdio> #include <cmath> #include <cstring> #include <algorithm> #include<map> #include<queue> using namespace std; const int N = 4e6+10, M = 30005, mod = 1e9 + 7, INF = 1e9+1000; typedef long long ll; int n,vis[N],a[N]; int tr[N],l[N],r[N],las[N]; ll sum[N]; void build(int k,int x,int y) { l[k] = x; r[k] = y; if(x==y) { sum[k]=a[a[x]];return ; } int mid = (x+y)>>1; build(k<<1,x,mid); build(k<<1|1,mid+1,y); sum[k] = sum[k<<1]+sum[k<<1|1]; } void update(int k,int x,int c) { if(x==l[k]&&x==r[k]) { sum[k] = c; return ; } int mid = (l[k]+r[k])/2; if(x<=mid) update(k<<1,x,c); else update(k<<1|1,x,c); sum[k] = sum[k<<1]+sum[k<<1|1]; } ll ask(int k,int s,int t) { if(l[k]==s&&t==r[k]) return sum[k]; int mid = (l[k]+r[k])>>1 ; ll ret = 0; if(t<=mid) ret = ask(k<<1,s,t); else if(s>mid) ret = ask(k<<1|1,s,t); else ret = ask(k<<1,s,mid)+ask(k<<1|1,mid+1,t); return ret; } int main() { int T; scanf("%d",&T); while(T--) { scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d",&a[i]); las[a[i]] = i; } build(1,1,n); int q; scanf("%d",&q); while(q--) { int op,l,r; scanf("%d%d%d",&op,&l,&r); if(op == 1) { int t1 = a[r]; int t2 = a[l]; swap(a[l],a[r]); update(1,l,a[t1]); update(1,r,a[t2]); las[a[l]] = l; las[a[r]] = r; update(1,las[l],a[l]); update(1,las[r],a[r]); } else { printf("%lld ",ask(1,l,r)); } } } }