BZOJ 2141 排队 线段树套替罪羊
Description
排排坐,吃果果,生果甜嗦嗦,大家笑呵呵。你一个,我一个,大的分给你,小的留给我,吃完果果唱支歌,大家乐和和。红星幼儿园的小朋友们排起了长长地队伍,准备吃果果。不过因为小朋友们的身高有所区别,排成的队伍高低错乱,极不美观。设第i个小朋友的身高为hi,我们定义一个序列的杂乱程度为:满足ihj的(i,j)数量。幼儿园阿姨每次会选出两个小朋友,交换他们的位置,请你帮忙计算出每次交换后,序列的杂乱程度。为方便幼儿园阿姨统计,在未进行任何交换操作时,你也应该输出该序列的杂乱程度。
Input
第一行为一个正整数n,表示小朋友的数量;第二行包含n个由空格分隔的正整数h1,h2,…,hn,依次表示初始队列中小朋友的身高;第三行为一个正整数m,表示交换操作的次数;以下m行每行包含两个正整数ai和bi¬,表示交换位置ai与位置bi的小朋友。
Output
输出文件共m行,第i行一个正整数表示交换操作i结束后,序列的杂乱程度。
Sample Input
【样例输入】
3
130 150 140
2
2 3
1 3
3
130 150 140
2
2 3
1 3
Sample Output
1
0
3
【样例说明】
未进行任何操作时,(2,3)满足条件;
操作1结束后,序列为130 140 150,不存在满足ihj的(i,j)对;
操作2结束后,序列为150 140 130,(1,2),(1,3),(2,3)共3对满足条件的(i,j)。
【数据规模和约定】
对于100%的数据,1≤m≤2*103,1≤n≤2*104,1≤hi≤109,ai≠bi,1≤ai,bi≤n。
数据结构的嵌套。外层位置线段树内层权值平衡树(替罪羊)然后考虑l,r删除或增加对答案的贡献,所以搞两个rank函数再xjb一搞就好了
0
3
【样例说明】
未进行任何操作时,(2,3)满足条件;
操作1结束后,序列为130 140 150,不存在满足ihj的(i,j)对;
操作2结束后,序列为150 140 130,(1,2),(1,3),(2,3)共3对满足条件的(i,j)。
【数据规模和约定】
对于100%的数据,1≤m≤2*103,1≤n≤2*104,1≤hi≤109,ai≠bi,1≤ai,bi≤n。
#include <cstring> #include <iostream> #include <stdio.h> #include <vector> using namespace std; const double alpha = 0.755; const int MAXN = 20005; int n,h[MAXN],len,m; long long Ans; template<typename _t> inline _t read(){ _t x = 0; int f = 1; char ch = getchar(); for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-f; for(;ch>='0'&&ch<='9';ch=getchar())x=(x*10)+(ch^48); return (_t)x*f; } struct node{ int s,cover,v,ex; node *ch[2]; void operator delete (void *p); void* operator new (size_t); bool bad(){ return ch[0]->cover > cover * alpha || ch[1]->cover > cover * alpha; } void Maintain(){ s = ch[0]->s+ch[1]->s+ex; cover =ch[0]->cover+ch[1]->cover+1; } node(){ s=v=cover=ex=0; ch[0]=ch[1]=NULL; } node(int x); }*null = new node(),*lst[MAXN<<5],*C,*mempool; vector<node*>q; void* node :: operator new (size_t){ node * p; if(!q.empty()){ p = q.back(); q.pop_back(); } else{ if(C==mempool){ C = new node[1<<15]; mempool = C + (1<<15); } p = C++; } return p; } void node :: operator delete (void *p){ q.push_back((node*)p); } node :: node(int x){ v=x;s=cover=ex=1; ch[0]=ch[1]=null; } void travel(node *p){ if(p == null)return; travel(p->ch[0]); if(p->ex)lst[++len] = p; else delete p; travel(p->ch[1]); } node *divide(int l,int r){ if(l>r)return null; int m = l + r >> 1; lst[m]->ch[0]=divide(l,m-1); lst[m]->ch[1]=divide(m+1,r); lst[m]->Maintain(); return lst[m]; } void rebuild(node *&o){ len = 0; travel(o); o=divide(1,len); } inline int rank_min(node *o,int x){ int Ans = 0; while(o!=null){ if(x<=o->v)o = o -> ch[0]; else Ans += o->ch[0]->s+o->ex,o = o->ch[1]; } return Ans; } inline int rank_max(node *o,int x){ int Ans = 0; while(o!=null){ if(x>=o->v)o = o->ch[1]; else Ans += o->ch[1]->s+o->ex,o=o->ch[0]; } return Ans; } node **insert(node *&o,int x){ if(o == null){ o = new node(x); return &null; } node **p = insert(o->ch[o->v<=x],x); if(o->bad())p = &o; o->Maintain(); return p; } void Insert(node *&o,int x){ node **p = insert(o,x); if(*p!=null)rebuild(*p); } void erase(node *o,int k){ if(o->ex && k == o->ch[0]->s +1){ o -> ex=0; o-> Maintain(); return; } if(o->ch[0]->s>=k)erase(o->ch[0],k); else erase(o->ch[1],k-o->ch[0]->s-o->ex); o -> Maintain(); } void Erase(node *&o,int x){ erase(o,rank_min(o,x)+1); if(o->s < o->cover *alpha)rebuild(o); } struct Tree{ int l,r,m; Tree *ls,*rs; node *root; void *operator new (size_t); Tree(){ ls=rs=NULL; root=null; m = l = r =0; } }*QAQ,*S,*T; void* Tree :: operator new (size_t){ if(S==T){ S = new Tree[1<<15]; T = S + (1<<15); } return S++; } void build(Tree *&o,int l,int r){ if(!o)o=new Tree; o->l=l,o->r=r,o->m=l+r>>1; for(int i=l;i<=r;i++)Insert(o->root,h[i]); if(l==r)return; build(o->ls,l,o->m); build(o->rs,o->m+1,r); } void Tree_insert(Tree *o,int x,int w){ Insert(o->root,w); if(o->l==o->r)return; if(x<=o->m)Tree_insert(o->ls,x,w); else Tree_insert(o->rs,x,w); } void Tree_erase(Tree *o,int x,int w){ Erase(o->root,w); if(o->l==o->r)return; if(x<=o->m)Tree_erase(o->ls,x,w); else Tree_erase(o->rs,x,w); } int Tree_max(Tree *o,int x,int y,int w){ if(x<=o->l&&o->r<=y)return rank_max(o->root,w); int ans = 0; if(x<=o->m)ans += Tree_max(o->ls,x,y,w); if(o->m<y)ans += Tree_max(o->rs,x,y,w); return ans; } int Tree_min(Tree *o,int x,int y,int w){ if(x<=o->l&&o->r<=y)return rank_min(o->root,w); int ans = 0; if(x<=o->m)ans += Tree_min(o->ls,x,y,w); if(o->m<y)ans += Tree_min(o->rs,x,y,w); return ans; } int main(){ scanf("%d",&n); for(int i=1;i<=n;i++)scanf("%d",&h[i]); build(QAQ,1,n); for(int i=2;i<=n;i++)Ans+=Tree_max(QAQ,1,i-1,h[i]); scanf("%d",&m); printf("%lld\n",Ans); while(m--){ int l,r; scanf("%d%d",&l,&r); if(l!=1)Ans-=Tree_max(QAQ,1,l-1,h[l]); if(l!=n)Ans-=Tree_min(QAQ,l+1,n,h[l]); Tree_erase(QAQ,l,h[l]); if(r!=1)Ans+=Tree_max(QAQ,1,r-1,h[l]); if(r!=n)Ans+=Tree_min(QAQ,r+1,n,h[l]); Tree_insert(QAQ,r,h[l]); if(l!=1)Ans+=Tree_max(QAQ,1,l-1,h[r]); if(l!=n)Ans+=Tree_min(QAQ,l+1,n,h[r]); Tree_erase(QAQ,r,h[r]); if(r!=1)Ans-=Tree_max(QAQ,1,r-1,h[r]); if(r!=n)Ans-=Tree_min(QAQ,r+1,n,h[r]); Tree_insert(QAQ,l,h[r]); swap(h[l],h[r]); printf("%lld\n",Ans); } }