TOJ 512. 樓層交換
===
###### tags: `Ans`
> 有一個序列 1...n
有兩種操作
1.swap(a,b) 把兩個東西互換
2.recorver(l,r)
l<=i<=r
如果這個位置 i 上不是 i
那就把位置 i 上的東西跟 i swap, 並且記有效次數1
請輸出每一次操作 2 的有效次數
N=5e5, Q=5e5
---
事實上假如 swap 操作 a 次
最多弄亂 2a 個東西
所以全部的 recover 操作最多做 2a 次即可
---
對於 l<=i<=r 找出所有 ouo[i] != i, 維護一個 set s
其中元素 k 代表 ouo[k]!=k
每當區間操作 用 lower_bound 把全部區間內數 k 拔出來放
然後 set 在 swap 的時候維護
---
```cpp
#include <bits/stdc++.h>
#define akiyama ios::sync_with_stdio(0), cin.tie(0);
#define all(x) x.begin(), x.end()
#define exi(x,s) (s.find(x) != x.end())
#define mem(a,x) memset(a,x,sizeof(a))
#define pb push_back
#define uset unordered_set
#define umap unordered_map
#define de(x) cout << #x << '=' << x << ", "
#define dend cout << "\n"
typedef long long ll;
using namespace std;
const int INF=0x7f7f7f7f, N = 5e5+10;
int ouo[N], pos[N], n, q;
set<int> s;
vector<int> v;
inline void print()
{
cout << "ouo: ";
for (int i=1; i<=n; i++) cout << ouo[i] << ' ';
cout << '\n';
cout << "pos: ";
for (int i=1; i<=n; i++) cout << pos[i] << ' ';
cout << '\n';
cout << "dif pos: ";
for (auto x: v) cout << x << ' ';
cout << '\n';
}
inline void mswap (int a, int b)
{
swap(pos[ouo[a]],pos[ouo[b]]);
swap(ouo[a],ouo[b]);
if (ouo[a] == a) s.erase(a);
else s.insert(a);
if (ouo[b] == b) s.erase(b);
else s.insert(b);
}
inline void recover(int l, int r)
{
int res = 0;
v.clear();
auto beg = s.lower_bound(l);
auto ed = s.upper_bound(r);
for (auto it = beg; it!=ed; it++) v.pb(*it);
for (auto t: v)
if (ouo[t]!=t)
mswap(t,pos[t]), res++;
cout << res << '\n';
}
int main()
{
akiyama;
cin >> n >> q;
for (int i=1; i<=n; i++) ouo[i] = i, pos[i] = i;
for (int i=0,opr,a,b; i<q; i++)
{
cin >> opr >> a >> b;
if (opr == 1) mswap(a,b);
else recover(a,b);
}
}
```