题目大意:给出一个数列,每次从这个序列中删掉一个数字,问每次删之前逆序对的数量是多少。
思路:这个题用CDQ分治是飞快的,然而我不知道怎么写。。于是就朴素的写了树套树。然后就朴素的被卡常了
内层用一个线段树。这个线段树不修改,一开始就要建好,然后线段树的每一个节点维护一个平衡树,存的是线段树存的区间中所有的值。
一开始先算一下逆序对数,然后每次删点的时候,先查询在这个点之前有多少大于他的,后面有多少小于他的,总的逆序对中将这些减掉。这个过程通过树套树不难实现。
CODE(交了这个代码T掉的,请选择在人多的时候先交一发糖果公园再交一次本题即可。。。因为多人测的时候会放宽一点时限。。。
你们感受一下
):
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define MAX 100010
using namespace std;
#define LEFT (pos << 1)
#define RIGHT (pos << 1|1)
#define SIZE(a) ((a) == NULL ? 0:a->size)
namespace IStream{
const int L=1<<15;
char buffer[L],*S,*T;
inline char Get_Char()
{
if(S==T)
{
T=(S=buffer)+fread(buffer,1,L,stdin);
if(S==T) return EOF;
}
return *S++;
}
inline int GetInt()
{
char c;
int re=0;
for(c=Get_Char();c<'0'||c>'9';c=Get_Char());
while(c>='0'&&c<='9')
re=(re<<1)+(re<<3)+(c-'0'),c=Get_Char();
return re;
}
}
/*class OStream{
private:
static const int L=1<<15;
char stack[20];int top;
char buffer[L],*S;
public:
OStream()
{
S=buffer;
}
void PutLongLong(long long x)
{
stack[++top]='\n';
if(!x) stack[++top]='0';
else while(x)
stack[++top]=x%10+'0',x/=10;
while(top)
{
if(S==buffer+L-1)
{
printf("%s",buffer);
S=buffer;
}
*S++=stack[top--];
}
}
~OStream()
{
*S=0;
puts(buffer);
}
}os;*/
int cnt,asks;
int src[MAX],pos[MAX];
int fenwick[MAX];
long long inv;
struct Treap{
int random,val,size;
Treap *son[2];
Treap(int _) {
val = _;
random = rand();
size = 1;
son[0] = son[1] = NULL;
}
int Compare(int x) {
if(x == val) return -1;
return x > val;
}
void Maintain() {
size = 1;
if(son[0] != NULL) size += son[0]->size;
if(son[1] != NULL) size += son[1]->size;
}
}*tree[MAX << 2];
inline int GetSum(int x)
{
int re = 0;
for(; x < MAX; x += x&-x)
re += fenwick[x];
return re;
}
inline void Fix(int x,int c)
{
for(; x; x -= x&-x)
fenwick[x] += c;
}
inline void Rotate(Treap *&a,bool dir)
{
Treap *k = a->son[!dir];
a->son[!dir] = k->son[dir];
k->son[dir] = a;
a->Maintain(),k->Maintain();
a = k;
}
void Insert(Treap *&a,int x)
{
if(a == NULL) {
a = new Treap(x);
return ;
}
int dir = a->Compare(x);
Insert(a->son[dir],x);
if(a->son[dir]->random > a->random)
Rotate(a,!dir);
a->Maintain();
}
void Delete(Treap *&a,int x)
{
int dir = a->Compare(x);
if(dir != -1)
Delete(a->son[dir],x);
else {
if(a->son[0] == NULL) a = a->son[1];
else if(a->son[1] == NULL) a = a->son[0];
else {
int _ = (a->son[0]->random > a->son[1]->random);
Rotate(a,_);
Delete(a->son[_],x);
}
}
if(a != NULL) a->Maintain();
}
int Ask(Treap *a,int x)
{
if(a == NULL) return 0;
if(a->val > x) return Ask(a->son[0],x);
if(a->val == x) return SIZE(a->son[0]);
return SIZE(a->son[0]) + 1 + Ask(a->son[1],x);
}
void BuildTree(int l,int r,int pos)
{
for(int i = l; i <= r; ++i)
Insert(tree[pos],src[i]);
if(l == r) return ;
int mid = (l + r) >> 1;
BuildTree(l,mid,LEFT);
BuildTree(mid + 1,r,RIGHT);
}
void Delete(int l,int r,int x,int pos,int c)
{
Delete(tree[pos],c);
if(l == r) return ;
int mid = (l + r) >> 1;
if(x <= mid) Delete(l,mid,x,LEFT,c);
else Delete(mid + 1,r,x,RIGHT,c);
}
int Ask(int l,int r,int x,int y,int pos,int c)
{
if(l == x && y == r)
return Ask(tree[pos],c);
int mid = (l + r) >> 1;
if(y <= mid) return Ask(l,mid,x,y,LEFT,c);
if(x > mid) return Ask(mid + 1,r,x,y,RIGHT,c);
int left = Ask(l,mid,x,mid,LEFT,c);
int right = Ask(mid + 1,r,mid + 1,y,RIGHT,c);
return left + right;
}
int main()
{
srand(19970815);
cin >> cnt >> asks;
for(int i = 1; i <= cnt; ++i) {
src[i] = IStream::GetInt();
//scanf("%d",&src[i]);
pos[src[i]] = i;
inv += GetSum(src[i]);
Fix(src[i],1);
}
BuildTree(1,cnt,1);
memset(fenwick,0,sizeof(fenwick));
for(int i = 1; i <= cnt; ++i)
Fix(i,1);
for(int x,i = 1; i <= asks; ++i) {
printf("%lld\n",inv);
//os.PutLongLong(inv);
x = IStream::GetInt();
//scanf("%d",&x);
Delete(1,cnt,pos[x],1,x);
Fix(pos[x],-1);
if(pos[x] != 1)
inv -= (GetSum(1) - GetSum(pos[x]) - Ask(1,cnt,1,pos[x] - 1,1,x));
if(pos[x] != cnt)
inv -= Ask(1,cnt,pos[x] + 1,cnt,1,x);
}
return 0;
}