题意:
给定n的两个排列, !@#¥%……&**(())*(&)+)*(&…………
http://acm.hdu.edu.cn/showproblem.php?pid=4988
思路:
先把所有数+1.....
两个排列假设是a和b,
先把a数组置换成1,2,3...n, 就是把a[i]换成i, 然后把b数组中等于a[i]的那个b[j]换成i, 然后如果只有一个询问的话就是求出b数组的逆序数。
每种交换都更新下逆序数就行了
对于第二种交换, 就是把b[i]和b[j]交换一下就行, 然后区间加加减减就可以了
对于第一种交换, 就是交换b数组里面的i和j
开一个数组记录一下on[i], 表示数i在b数组里面的下标,然后i=on[i], j=on[j], 就变成第一种交换了。
昨晚刚看了大白的uva11990 , 照着它的思路敲了下uva11990, 但是uva卡到爆, 没交上, 今天BC就来了个类似的,没搞出来可惜了。
虽然昨天刚敲了, 但是今天却完全想不到那个思路, 还很sb地用主席树维护, 智商捉急啊
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#include <vector>
#include <set>
#include <cstdlib>
using namespace std;
#define inf 0x3f3f3f3f
#define LL long long
#define mxn 100020
#define ls ( p[i].ch[0] )
#define rs ( p[i].ch[1] )
struct node {
int ch[2];
int r, v, s;
node() {}
node( int v ): v( v ) {
ch[0] = ch[1] = 0;
r = rand();
s = 1;
}
}p[mxn*80];
int sz;
int creat( int v ) {
++ sz;
p[sz] = node( v );
return sz;
}
int cmp( int i, int v ) {
if( p[i].v == v )
return -1;
return v < p[i].v ? 0: 1;
}
void mt( int i ) {
p[i].s = 1;
if( ls )
p[i].s += p[ls].s;
if( rs )
p[i].s += p[rs].s;
}
void rt( int &i, int d ) {
int k = p[i].ch[d^1];
p[i].ch[d^1] = p[k].ch[d];
p[k].ch[d] = i;
mt( i ), mt( k );
i = k;
}
void insert( int &i, int v ) {
if( !i ) {
i = creat( v );
return ;
}
int d = cmp( i, v );
insert( p[i].ch[d], v );
if( p[p[i].ch[d]].r > p[i].r )
rt( i, d ^ 1 );
mt( i );
}
void Remove( int &i, int v ) {
int d = cmp( i, v );
if( !~d ) {
if( !ls )
i = rs;
else if( !rs )
i = ls;
else {
int d2 = p[ls].r > p[rs].r ? 1: 0;
rt( i, d2 );
Remove( p[i].ch[d2], v );
}
}
else
Remove( p[i].ch[d], v );
if( i )
mt( i );
}
// 小于v的数的个数
int Low( int i, int v ) {
if( !i )
return 0;
int d = cmp( i, v );
int ret = 0;
if( ls )
ret += p[ls].s;
if( !~d ) {
return ret + 1;
}
if( d == 0 )
return Low( ls, v );
return ret + 1 + Low( rs, v );
}
// 大于v的数的个数
int Up( int i, int v ) {
if( !i )
return 0;
int d = cmp( i, v );
int ret = 0;
if( rs )
ret += p[rs].s;
if( !~d )
return ret + 1;
if( d == 1 )
return Up( rs, v );
return ret + 1 + Up( ls, v );
}
int a[mxn], b[mxn], on[mxn];
int r[mxn], n;
int root[mxn];
int lb( int x ) {
return x & -x;
}
void read() {
for( int i = 1; i <= n; ++i ) {
scanf( "%d", &a[i] );
++ a[i];
}
for( int i = 1; i <= n; ++i ) {
scanf( "%d", &b[i] );
++ b[i];
}
for( int i = 1; i <= n; ++i )
r[a[i]] = i;
for( int i = 1; i <= n; ++i ) {
b[i] = r[b[i]]; // 置换b数组
on[b[i]] = i; // on[i] 表示 数i的下标
}
}
// 更新。。
void update( int x, int v, int d ) {
while( x <= n ) {
if( d == -1 )
Remove( root[x], v );
else
insert( root[x], v );
x += lb( x );
}
}
int low( int x, int v ) {
int ret = 0;
while( x ) {
ret += Low( root[x], v );
x -= lb( x );
}
return ret;
}
int up( int x, int v ) {
int ret = 0;
while( x ) {
ret += Up( root[x], v );
x -= lb( x );
}
return ret;
}
int main() {
while( scanf( "%d", &n ) != EOF ) {
sz = 0;
read();
LL ans = 0;
memset( root, 0, sizeof( root ) );
// treap + 树状数组
for( int i = 1; i <= n; ++i ) {
for( int j = i - lb( i ) + 1; j <= i; ++j )
insert( root[i], b[j] );
}
for( int i = 2; i <= n; ++i )
ans += up( i - 1, b[i] );
int m;
scanf( "%d", &m );
while( m-- ) {
char s[10];
scanf( "%s", s );
if( s[0] == 'Q' ) {
printf( "%I64d\n", ans );
continue;
}
int p, x, y;
scanf( "%d%d%d", &p, &x, &y );
x ++, y++;
if( x == y )
continue;
if( p == 0 ) {
x = on[x], y = on[y];
}
if( x > y )
swap( x, y );
if( y - x > 1 ) {
ans -= low( y - 1, b[x] ) - low( x, b[x] );
ans += up( y - 1, b[x] ) - up( x, b[x] );
ans -= up( y - 1, b[y] ) - up( x, b[y] );
ans += low( y - 1, b[y] ) - low( x, b[y] );
}
if( b[x] < b[y] )
ans ++;
else
ans --;
update( x, b[x], -1 );
update( y, b[y], -1 );
update( x, b[y], 1 );
update( y, b[x], 1 );
swap( on[b[x]], on[b[y]] ); // 要先更新on数组
swap( b[x], b[y] );
}
}
return 0;
}