hdu_5193_Go to movies Ⅱ(带插入删除的逆序对,块状链表)
题意:
有n个人站成一排,每个人的身高为Hi。每次有人加入或者有人离开,就要判断有多少人站反了(i < j&&Hi>Hj)
第一行n,m,接下来n个整数(n,m<=2e4)
接下来m行,
0 x y 表示有一个身高为y的人插在x后面,x=0表示插在最前面。(1≤y≤n)
1 x 表示第x个人(从左到右)离开。
题解:
官方题解:
添加或者删除一个元素时,维护逆序对时,需要知道在它之前有多少个数比它大,在它之后有多少个数比他小。有下标和权值两个维度,可以使用两个数据结构嵌套。题目中n=20000,范围不大,外层可以使用分块维护下标,这样添加和删除元素的时候,
也很方便,直接暴力。查找权值个数时,使用树状数组比较方便。内层通过树状数组维护权值。设每块的大小为S,那么删除或者添加元素时,维护逆序对数的复杂度是O(S+P∗logn),S是块内直接暴力更新逆序对的代价,
P/S∗logn在前面块找比它大和在后面块中找比它小的代价,P表示当前元素的个数。为了使这两部分复杂度尽量均摊让S=P/S∗logn,S取根号Plogn
。直接通过分块暴力添加和删除时,块的大小会退化,需要重构,。重构一次的复杂度是S*logn, 总的重构复杂度是,与添加和删除总的复杂度一至。因此整个问题的复杂度为O(m√nlogn).
1 #include<bits/stdc++.h> 2 #define F(i,a,b) for(int i=a;i<=b;i++) 3 using namespace std; 4 5 const int N=20010,sqr=800; 6 int ans,tot,n,flag,op,x,y,m; 7 8 inline void add(int *c,int x,int v){while(x<=n)c[x]+=v,x+=x&-x;} 9 10 inline int sum(int *c,int x){int an=0;while(x>0)an+=c[x],x-=(x&-x);return an;} 11 12 struct node 13 { 14 int dt[sqr+10],sz,c[N],nxt,pre; 15 void init(){memset(c,0,sizeof(c)),sz=0,pre=0,nxt=0;} 16 }b[400]; 17 18 int getpos(int &x) 19 { 20 int i=1; 21 while(b[i].sz<x&&b[i].nxt)x-=b[i].sz,i=b[i].nxt; 22 return i; 23 } 24 25 int cal(int x) 26 { 27 int an=0; 28 int id=getpos(x); 29 F(i,1,x-1)if(b[id].dt[i]>b[id].dt[x])an++; 30 F(i,x+1,b[id].sz)if(b[id].dt[i]<b[id].dt[x])an++; 31 for(int i=1;i!=id;i=b[i].nxt) 32 an+=sum(b[i].c,n)-sum(b[i].c,b[id].dt[x]); 33 for(int i=b[id].nxt;i!=0;i=b[i].nxt) 34 an+=sum(b[i].c,b[id].dt[x]-1); 35 return an; 36 } 37 38 void del(int x){ 39 ans-=cal(x); 40 int id=getpos(x); 41 add(b[id].c,b[id].dt[x],-1); 42 F(i,x+1,b[id].sz)b[id].dt[i-1]=b[id].dt[i]; 43 b[id].sz--; 44 if(b[id].sz==0)//删除块 45 { 46 int pre=b[id].pre,net=b[id].nxt; 47 b[net].pre=pre,b[pre].nxt=net; 48 } 49 } 50 51 void ins(int x,int y) 52 { 53 int xx=x; 54 if(flag==0) 55 { 56 b[1].init(),b[1].dt[++b[1].sz]=y; 57 add(b[1].c,b[1].dt[1],1),flag=1; 58 return; 59 } 60 int id=getpos(x);//在第几个块 61 if(b[id].sz==sqr)//块分裂 62 { 63 b[++tot].init(),b[id].sz++; 64 int cnt=0; 65 for(int i=b[id].sz;i>x;i--) 66 b[id].dt[i]=b[id].dt[i-1]; 67 b[id].dt[x]=y; 68 add(b[id].c,b[id].dt[x],1); 69 int len=b[id].sz/2; 70 F(i,len+1,b[id].sz) 71 { 72 b[tot].dt[++cnt]=b[id].dt[i]; 73 add(b[tot].c,b[id].dt[i],1); 74 add(b[id].c,b[id].dt[i],-1); 75 } 76 b[tot].sz=cnt,b[tot].nxt=b[id].nxt; 77 b[id].nxt=tot,b[id].sz=len,b[tot].pre=id; 78 } 79 else{ 80 b[id].sz++; 81 for(int i=b[id].sz;i>x;i--) 82 b[id].dt[i]=b[id].dt[i-1]; 83 b[id].dt[x]=y; 84 add(b[id].c,b[id].dt[x],1); 85 } 86 ans+=cal(xx); 87 } 88 89 int main(){ 90 while(~scanf("%d%d",&n,&m)) 91 { 92 ans=0,tot=1,b[1].sz=0,flag=0; 93 F(i,1,n)scanf("%d",&y),ins(i,y); 94 F(i,1,m) 95 { 96 scanf("%d",&op); 97 if(op==0)scanf("%d%d",&x,&y),ins(x+1,y); 98 else scanf("%d",&x),del(x); 99 printf("%d\n",ans); 100 } 101 } 102 return 0; 103 }