树套树。
每次删掉x的时候会减去1到x-1里比x位置的数大的数和它构成的逆序对,以及x+1到n里比x位置的数小的数和它构成的逆序对。
顺带一提我发现平衡树insert的时候不是要splay一下嘛
如果改成每插入50个splay一下会快的飞起
我这道题就是这么卡过去的23333
放上代码
#include<cstdio> #include<cstdlib> #include<cstring> #include<cctype> #include<algorithm> #define mid ((l+r)>>1) #define left (rt<<1) #define right (rt<<1|1) #define lson l,mid,left #define rson mid+1,r,right using namespace std; int CNT; inline long long read(){ long long num=0,f=1; char ch=getchar(); while(!isdigit(ch)){ if(ch=='-') f=-1; ch=getchar(); } while(isdigit(ch)){ num=num*10+ch-'0'; ch=getchar(); } return num*f; } int root[1000000]; int q[100010]; struct Splay{ struct Node{ int size,sum,e[2],val,fa; }tree[1000000]; int point,tot; Splay(){ point=tot=0; } inline int iden(int x){ return x==tree[tree[x].fa].e[1]; } inline void connect(int x,int fa,int how){ tree[x].fa=fa; tree[fa].e[how]=x; } inline void update(int x){ tree[x].size=tree[x].sum; if(tree[x].e[0]) tree[x].size+=tree[tree[x].e[0]].size; if(tree[x].e[1]) tree[x].size+=tree[tree[x].e[1]].size; } void rotate(int x,int rt){ int y=tree[x].fa; int r=tree[y].fa; if(root[rt]==y) root[rt]=x; int sony=iden(x),sonr=iden(y); int b=tree[x].e[sony^1]; connect(b,y,sony); connect(y,x,sony^1); connect(x,r,sonr); update(y);update(x); } void splay(int pos,int to,int rt){ to=tree[to].fa; while(tree[pos].fa!=to){ if(tree[tree[pos].fa].fa==to) rotate(pos,rt); else if(iden(pos)==iden(tree[pos].fa)){ rotate(tree[pos].fa,rt); rotate(pos,rt); } else{ rotate(pos,rt); rotate(pos,rt); } } } int create(int val,int fa){ tree[++tot].val=val; tree[tot].sum=tree[tot].size=1; tree[tot].fa=fa; return tot; } int find(int val,int rt){ int now=root[rt]; while(1){ if(!now) return 0; if(tree[now].val==val){ splay(now,root[rt],rt); return now; } int nxt=val>tree[now].val?1:0; if(!tree[now].e[nxt]) return 0; now=tree[now].e[nxt]; } } int build(int val,int rt){ point++; if(!root[rt]){ root[rt]=create(val,0); return root[rt]; } int now=root[rt]; while(1){ tree[now].size++; if(tree[now].val==val){ tree[now].sum++; return now; } int nxt=val>tree[now].val?1:0; if(!tree[now].e[nxt]){ int p=create(val,now); connect(p,now,nxt); return p; } now=tree[now].e[nxt]; } } void insert(int val,int rt){ int p=build(val,rt); if((++CNT)%50==0){ splay(p,root[rt],rt); CNT=0; } } void dele(int x){ tree[x].e[0]=tree[x].e[1]=0; if(x==tot) tot--; } void pop(int val,int rt){ int deal=find(val,rt); if(!deal) return; point--; if(tree[deal].sum>1){ tree[deal].sum--; tree[deal].size--; return;} if(!tree[deal].e[0]){ root[rt]=tree[deal].e[1]; tree[root[rt]].fa=0; } else{ int le=tree[deal].e[0]; while(tree[le].e[1]) le=tree[le].e[1]; splay(le,tree[deal].e[0],rt); int ri=tree[deal].e[1]; connect(ri,le,1); tree[le].fa=0; root[rt]=le; update(le); } dele(deal); } int rank(int val,int rt){ int ans=0,now=root[rt]; while(1){ if(!now) return ans; if(tree[now].val==val){ ans+=tree[tree[now].e[0]].size; return ans; } if(val<tree[now].val) now=tree[now].e[0]; else{ ans+=tree[tree[now].e[0]].size+tree[now].sum; now=tree[now].e[1]; } } } int arank(int val,int rt){ int ans=0,now=root[rt]; while(1){ if(!now) return ans; if(tree[now].val==val){ ans+=tree[tree[now].e[1]].size; return ans; } if(val<tree[now].val){ ans+=tree[tree[now].e[1]].size+tree[now].sum; now=tree[now].e[0]; } else now=tree[now].e[1]; } } int ask(int val,int rt,int opt){ if(opt==1) return arank(val,rt); else return rank(val,rt); } }s; void build(int l,int r,int rt){ for(int i=l;i<=r;++i) s.insert(q[i],rt); if(l==r) return; build(lson); build(rson); } int query(int from,int to,int val,int l,int r,int rt,int opt){ if(from>to) return 0; if(from<=l&&to>=r) return s.ask(val,rt,opt); int cnt=0; if(from<=mid) cnt+=query(from,to,val,lson,opt); if(to>mid) cnt+=query(from,to,val,rson,opt); return cnt; } void Delete(int o,int val,int l,int r,int rt){ s.pop(val,rt); if(l==r) return; if(o<=mid) Delete(o,val,lson); else Delete(o,val,rson); } int ans; int main(){ int n=read(),m=read(); for(int i=1;i<=n;++i) q[i]=read(); build(1,n,1); for(int i=1;i<=n;++i) ans+=query(1,i-1,q[i],1,n,1,1); printf("%d",ans); for(int i=1;i<=m;++i){ int pos=read(); ans-=query(1,pos-1,q[pos],1,n,1,1); ans-=query(pos+1,n,q[pos],1,n,1,0); printf(" %d",ans); Delete(pos,q[pos],1,n,1); } return 0; }