LG P1975 [国家集训队]排队
Description
排排坐,吃果果,生果甜嗦嗦,大家笑呵呵。你一个,我一个,大的分给你,小的留给我,吃完果果唱支歌,大家乐和和。
红星幼儿园的小朋友们排起了长长地队伍,准备吃果果。不过因为小朋友们的身高有所区别,排成的队伍高低错乱,极不美观。设第 ii个小朋友的身高为 hi。
幼儿园阿姨每次会选出两个小朋友,交换他们的位置,请你帮忙计算出每次交换后,序列的逆序对数。为方便幼儿园阿姨统计,在未进行任何交换操作时,你也应该输出该序列的逆序对数。
Solution
这道题最经典的做法就是树状数组套平衡树了,做法与动态逆序对比较像 考虑交换两个数之后产生的贡献:
不妨设 $a<b$,
原来的区间$[a,b]$中:
比$h[b]$小的数,原来不组成逆序对,交换之后组成了
比$h[b]$大的数,原来组成逆序对,交换之后消失了
比$h[a]$大的数,原来不组成逆序对,交换之后组成了
比$h[a]$小的数,原来组成逆序对,交换之后消失了
分别统计计算贡献,我的树状数组以身高为下标,每个位置存放一个平衡树存储该身高出现的位置。
不要忘记计算两个人交换时这两个人组成的逆序对产生的贡献
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<algorithm> 2 #include<iostream> 3 #include<cstdlib> 4 #include<cstdio> 5 using namespace std; 6 int n,m,h[20005],s[20005],ans[2005],bit[20005],tot,root[20005],cnt; 7 struct BST 8 { 9 int key,siz,val,child[2]; 10 }treap[4000005]; 11 inline int read() 12 { 13 int f=1,w=0; 14 char ch=0; 15 while(ch<'0'||ch>'9') 16 { 17 if(ch=='-') 18 f=-1; 19 ch=getchar(); 20 } 21 while(ch>='0'&&ch<='9') 22 { 23 w=(w<<1)+(w<<3)+ch-'0'; 24 ch=getchar(); 25 } 26 return f*w; 27 } 28 int lowbit(int x) 29 { 30 return x&-x; 31 } 32 int query(int x) 33 { 34 int ret=0; 35 while(x) 36 { 37 ret+=bit[x]; 38 x-=lowbit(x); 39 } 40 return ret; 41 } 42 void add(int x) 43 { 44 while(x<=tot) 45 { 46 bit[x]++; 47 x+=lowbit(x); 48 } 49 } 50 void pushup(int rt) 51 { 52 treap[rt].siz=treap[treap[rt].child[0]].siz+treap[treap[rt].child[1]].siz+1; 53 } 54 void split(int rt,int &x,int &y,int v) 55 { 56 if(!rt) 57 { 58 x=y=0; 59 return; 60 } 61 if(treap[rt].val<=v) 62 { 63 x=rt; 64 split(treap[rt].child[1],treap[x].child[1],y,v); 65 } 66 else 67 { 68 y=rt; 69 split(treap[rt].child[0],x,treap[y].child[0],v); 70 } 71 pushup(rt); 72 } 73 void merge(int &rt,int x,int y) 74 { 75 if(!x||!y) 76 { 77 rt=x+y; 78 return; 79 } 80 if(treap[x].key<treap[y].key) 81 { 82 rt=x; 83 merge(treap[rt].child[1],treap[x].child[1],y); 84 } 85 else 86 { 87 rt=y; 88 merge(treap[rt].child[0],x,treap[y].child[0]); 89 } 90 pushup(rt); 91 } 92 int check(int &rt,int l,int r) 93 { 94 int x=0,y=0,z=0; 95 split(rt,x,z,r); 96 split(x,x,y,l-1); 97 int ret=treap[y].siz; 98 merge(x,x,y); 99 merge(rt,x,z); 100 return ret; 101 } 102 int queryarr(int x,int l,int r) 103 { 104 int ret=0; 105 while(x) 106 { 107 ret+=check(root[x],l,r); 108 x-=lowbit(x); 109 } 110 return ret; 111 } 112 void erase(int &rt,int v) 113 { 114 int x=0,y=0,z=0; 115 split(rt,x,z,v); 116 split(x,x,y,v-1); 117 merge(y,treap[y].child[0],treap[y].child[1]); 118 merge(x,x,y); 119 merge(rt,x,z); 120 } 121 void insert(int &rt,int v) 122 { 123 int x=0,y=0,z=++cnt; 124 treap[z].siz=1; 125 treap[z].val=v; 126 treap[z].key=rand(); 127 split(rt,x,y,v); 128 merge(x,x,z); 129 merge(rt,x,y); 130 } 131 void addarr(int x,int pos,int v) 132 { 133 while(x<=tot) 134 { 135 if(v==-1) 136 erase(root[x],pos); 137 else 138 insert(root[x],pos); 139 x+=lowbit(x); 140 } 141 } 142 int main() 143 { 144 n=read(); 145 for(int i=1;i<=n;i++) 146 s[i]=h[i]=read(); 147 sort(s+1,s+n+1); 148 tot=unique(s+1,s+1+n)-s-1; 149 for(int i=1;i<=n;i++) 150 h[i]=lower_bound(s+1,s+1+tot,h[i])-s; 151 for(int i=1;i<=n;i++) 152 { 153 ans[0]+=query(tot)-query(h[i]); 154 add(h[i]); 155 addarr(h[i],i,1); 156 } 157 printf("%d\n",ans[0]); 158 m=read(); 159 for(int i=1;i<=m;i++) 160 { 161 ans[i]=ans[i-1]; 162 int a=read(),b=read(); 163 if(a>b) 164 swap(a,b); 165 if(b-a>1) 166 { 167 ans[i]+=queryarr(h[b]-1,a+1,b-1); 168 ans[i]-=queryarr(tot,a+1,b-1)-queryarr(h[b],a+1,b-1); 169 ans[i]-=queryarr(h[a]-1,a+1,b-1); 170 ans[i]+=queryarr(tot,a+1,b-1)-queryarr(h[a],a+1,b-1); 171 } 172 addarr(h[a],a,-1); 173 addarr(h[b],b,-1); 174 addarr(h[a],b,1); 175 addarr(h[b],a,1); 176 if(h[a]<h[b]) 177 ans[i]++; 178 else if(h[a]>h[b]) 179 ans[i]--; 180 swap(h[a],h[b]); 181 printf("%d\n",ans[i]); 182 } 183 return 0; 184 }