【bzoj2141】排队 [国家集训队2011]排队(魏铭) 树套树 线段树套替罪羊树
这个题就是动态偏序对,每次操作做两个删除两个插入就好了。
#include<cstdio> #include<iostream> #include<cstring> #define MAXN 100010 using namespace std; typedef long long LL; typedef double D; const D a=0.756; LL ans; struct ScapeGoat_Tree { ScapeGoat_Tree *ch[2]; int key,size,cover,ex; bool bad() { return cover*a+5<ch[0]->cover||cover*a+5<ch[1]->cover; } void pushup() { size=ch[0]->size+ch[1]->size+ex; cover=ch[0]->cover+ch[1]->cover+1; } }*null,*stack[(MAXN<<5)+5],pool[(MAXN<<5)+5],*lst[(MAXN<<4)+5]; int top,len; inline void Init() { null=pool; null->ch[1]=null->ch[0]=null; null->key=null->size=null->cover=null->ex=0; for(int i=1;i<(MAXN<<5);i++)stack[++top]=pool+i; } inline ScapeGoat_Tree *New(int key) { ScapeGoat_Tree *p=stack[top--]; p->ch[1]=p->ch[0]=null; p->key=key; p->size=p->ex=p->cover=1; return p; } struct Tree { Tree *ch[2]; int mid,l,r; ScapeGoat_Tree *root; Tree(){ch[1]=ch[0]=NULL;mid=l=r=0;root=null;} void* operator new(size_t size); }*root,*C,*mempool; void* Tree :: operator new(size_t size) { if(C==mempool) { C=new Tree[(1<<15)+5]; mempool=C+(1<<15)+5; } C->root=null; return C++; } void travel(ScapeGoat_Tree *p) { if(p==null)return; travel(p->ch[0]); if(p->ex)lst[++len]=p; else stack[++top]=p; travel(p->ch[1]); } ScapeGoat_Tree *divide(int l,int r) { if(l>r)return null; int mid=(l+r)>>1; lst[mid]->ch[0]=divide(l,mid-1); lst[mid]->ch[1]=divide(mid+1,r); lst[mid]->pushup(); return lst[mid]; } inline void rebuild(ScapeGoat_Tree *&p) { len=0; travel(p); p=divide(1,len); } ScapeGoat_Tree **insert(ScapeGoat_Tree *&p,int key) { if(p==null ) { p=New(key); return &null; } p->size++; p->cover++; ScapeGoat_Tree **ret=insert(p->ch[p->key<=key],key); if(p->bad())ret=&p; return ret; } inline void Insert(ScapeGoat_Tree *&Root,int key) { ScapeGoat_Tree **p=insert(Root,key); if(*p!=null )rebuild(*p); } inline int Rank_Max(ScapeGoat_Tree *Root,int key) { ScapeGoat_Tree *now=Root; int ret=0; while(now!=null ) if(now->key<=key) now=now->ch[1]; else ret+=now->ch[1]->size+now->ex,now=now->ch[0]; return ret; } inline int Rank_Min(ScapeGoat_Tree *Root,int key) { ScapeGoat_Tree *now=Root; int ret=0; while(now!=null ) if(now->key>=key) now=now->ch[0]; else ret+=now->ch[0]->size+now->ex,now=now->ch[1]; return ret; } void del(ScapeGoat_Tree *p,int k) { p->size--; if(p->ex&&p->ch[0]->size+1==k) { p->ex=0; return; } if(p->ch[0]->size>=k) del(p->ch[0],k); else del(p->ch[1],k-p->ch[0]->size-p->ex); } inline void Del(ScapeGoat_Tree *&Root,int key) { del(Root,Rank_Min(Root,key)+1); if(Root->size<Root->cover*a)rebuild(Root); } int n,m,pos[MAXN]; void build(Tree *p) { p->mid=(p->l+p->r)>>1; if(p->l==p->r)return; p->ch[0]=new Tree; p->ch[0]->l=p->l; p->ch[0]->r=p->mid; p->ch[1]=new Tree; p->ch[1]->l=p->mid+1; p->ch[1]->r=p->r; build(p->ch[0]); build(p->ch[1]); } void Ins(Tree *p,int key,int aim) { Insert(p->root,key); if(p->l==p->r)return; Ins(p->ch[p->mid<aim],key,aim); } int query_Max(int l,int r,int key,Tree *p) { if(l<=p->l&&p->r<=r) return Rank_Max(p->root,key); int tmp=0; if(l<=p->mid)tmp+=query_Max(l,r,key,p->ch[0]); if(p->mid<r)tmp+=query_Max(l,r,key,p->ch[1]); return tmp; } int query_Min(int l,int r,int key,Tree *p) { if(l<=p->l&&p->r<=r) return Rank_Min(p->root,key); int tmp=0; if(l<=p->mid)tmp+=query_Min(l,r,key,p->ch[0]); if(p->mid<r)tmp+=query_Min(l,r,key,p->ch[1]); return tmp; } void Delete(Tree *p,int key,int aim) { Del(p->root,key); if(p->l==p->r)return; Delete(p->ch[p->mid<aim],key,aim); } int main() { //freopen("nt2011_queue.in","r",stdin); //freopen("nt2011_queue.out","w",stdout); Init(); scanf("%d",&n); root=new Tree; root->l=1; root->r=n; build(root); for(int i=1;i<=n;i++) { int x; scanf("%d",&x); pos[i]=x; Ins(root,x,i); if(i!=1)ans+=query_Max(1,i-1,x,root); } scanf("%d",&m); for(int i=1;i<=m;i++) { printf("%lld\n",ans); int x,y; scanf("%d%d",&x,&y); if(x!=1) ans-=query_Max(1,x-1,pos[x],root); if(x!=n) ans-=query_Min(x+1,n,pos[x],root); Delete(root,pos[x],x); if(y!=1) ans-=query_Max(1,y-1,pos[y],root); if(y!=n) ans-=query_Min(y+1,n,pos[y],root); Delete(root,pos[y],y); swap(pos[x],pos[y]); Ins(root,pos[x],x); if(x!=1) ans+=query_Max(1,x-1,pos[x],root); if(x!=n) ans+=query_Min(x+1,n,pos[x],root); Ins(root,pos[y],y); if(y!=1) ans+=query_Max(1,y-1,pos[y],root); if(y!=n) ans+=query_Min(y+1,n,pos[y],root); } printf("%lld\n",ans); return 0; }
苟利国家生死以, 岂因祸福避趋之。