LG P1975 [国家集训队]排队

Description

排排坐,吃果果,生果甜嗦嗦,大家笑呵呵。你一个,我一个,大的分给你,小的留给我,吃完果果唱支歌,大家乐和和。

红星幼儿园的小朋友们排起了长长地队伍,准备吃果果。不过因为小朋友们的身高有所区别,排成的队伍高低错乱,极不美观。设第 ii个小朋友的身高为 hi

幼儿园阿姨每次会选出两个小朋友,交换他们的位置,请你帮忙计算出每次交换后,序列的逆序对数。为方便幼儿园阿姨统计,在未进行任何交换操作时,你也应该输出该序列的逆序对数。

Solution

这道题最经典的做法就是树状数组套平衡树了,做法与动态逆序对比较像 考虑交换两个数之后产生的贡献:

不妨设 $a<b$

原来的区间$[a,b]$中:

比$h[b]$小的数,原来不组成逆序对,交换之后组成了

比$h[b]$大的数,原来组成逆序对,交换之后消失了

比$h[a]$大的数,原来不组成逆序对,交换之后组成了

比$h[a]$小的数,原来组成逆序对,交换之后消失了

分别统计计算贡献,我的树状数组以身高为下标,每个位置存放一个平衡树存储该身高出现的位置。

不要忘记计算两个人交换时这两个人组成的逆序对产生的贡献

  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
",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
",ans[i]);
182     }
183     return 0;
184 }
P1975 【[国家集训队]排队】
原文地址:https://www.cnblogs.com/JDFZ-ZZ/p/13301569.html