生活随笔
收集整理的這篇文章主要介紹了
Squared Permutation(线段树)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
鏈接:https://ac.nowcoder.com/acm/problem/14113
來源:牛客網
題目描述
最近,無聊的過河船同學在玩一種奇怪的名為“小Q的惡作劇”的紙牌游戲。
現在過河船同學手有n張牌,分別寫著1,2,3,…,n,打亂順序之后排成一行,位置從左往右按照1,2,3,…,n標號。
接下來小Q同學會給出q個操作,分為以下兩種:
1.給定l,r(1 ≤ l<r ≤ n),交換從左往右數的第l和第r張牌,
2.給定l,r(1 ≤ l ≤ r ≤ n),對從左往右數的第i(l ≤ i ≤ r)張牌,記下位置是這張牌上的數字的牌的數字,詢問所有記下的數字加起來的結果。
雖然無聊的過河船同學精通四則運算,但是要完成這么大的計算量還是太辛苦了,希望你能幫他處理這些操作。
輸入描述:
第一行是一個正整數T(≤ 10),表示測試數據的組數,
對于每組測試數據,
第一行是一個整數n(1 ≤ n ≤ 100000),
第二行包含一個1,2,3,…,n的排列,其中第i個數表示第i張牌上的數字,
第三行是一個整數q(0 ≤ q ≤ 100000),表示操作數,
接下來q行,每行包含三個整數op(1 ≤ op ≤ 2),l,r,其中op表示操作的類型。
輸出描述:
對于每組測試數據,依次輸出所有查詢操作的結果,每個結果一行。
示例1
輸入
復制
1
3
1 2 3
3
2 1 2
1 1 3
2 2 3
輸出
復制
3
5
說明
第二次操作后牌上的數字從左往右依次是3,2,1,
第三次操作的結果是位置是第2張牌上的數字的牌的數字加上位置是第3張牌上的數字的牌的數字,也就是第2張牌上的數字加上第1張牌上的數字,結果是5。
很扯淡的一道題,卡了很久。
一開始就是單純的把兩個位置的交換過來。但是wa了之后手畫了幾組樣例,發現單純的交換不行,會有后效性,于是手動模擬了幾組樣例,發現除了交換l,r兩個位置上的數字不行,還要交換l和r兩個數字在數組中的位置posl,posr上的數字。自己找的規律,不知道咋證明。路過的大佬指點一波。
代碼如下:
#include<bits/stdc++.h>
#define ll long long
using namespace std
;const int maxx
=1e5+100;
struct node
{int l
;int r
;ll sum
;
}p
[maxx
<<2];
int a
[maxx
];
int b
[maxx
];
int n
,m
;inline void pushup(int cur
)
{p
[cur
].sum
=p
[cur
<<1].sum
+p
[cur
<<1|1].sum
;
}
inline void build(int l
,int r
,int cur
)
{p
[cur
].l
=l
;p
[cur
].r
=r
;p
[cur
].sum
=0;if(l
==r
){p
[cur
].sum
=1ll*a
[a
[l
]];return ;}int mid
=l
+r
>>1;build(l
,mid
,cur
<<1);build(mid
+1,r
,cur
<<1|1);pushup(cur
);
}
inline void update(int pos
,int cur
)
{int L
=p
[cur
].l
;int R
=p
[cur
].r
;if(L
==R
){p
[cur
].sum
=1ll*a
[a
[L
]];return ;}int mid
=L
+R
>>1;if(pos
<=mid
) update(pos
,cur
<<1);else update(pos
,cur
<<1|1);pushup(cur
);
}
inline ll
query(int l
,int r
,int cur
)
{int L
=p
[cur
].l
;int R
=p
[cur
].r
;if(l
<=L
&&R
<=r
) return p
[cur
].sum
;int mid
=L
+R
>>1;if(r
<=mid
) return query(l
,r
,cur
<<1);else if(l
>mid
) return query(l
,r
,cur
<<1|1);else return (query(l
,mid
,cur
<<1)+query(mid
+1,r
,cur
<<1|1));
}
int main()
{int t
,op
,l
,r
;scanf("%d",&t
);while(t
--){scanf("%d",&n
);for(int i
=1;i
<=n
;i
++) scanf("%d",&a
[i
]),b
[a
[i
]]=i
;build(1,n
,1);scanf("%d",&m
);while(m
--){scanf("%d%d%d",&op
,&l
,&r
);if(op
==1){int x
=a
[l
];a
[l
]=a
[r
];a
[r
]=x
;b
[a
[r
]]=r
;b
[a
[l
]]=l
;update(l
,1);update(r
,1);update(b
[l
],1);update(b
[r
],1);}else if(op
==2){printf("%lld\n",query(l
,r
,1));}}}return 0;
}
努力加油a啊,(o)/~
總結
以上是生活随笔為你收集整理的Squared Permutation(线段树)的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。