BZOJ3787:Gty的文艺妹子序列(分块,树状数组)

Description

Autumn终于会求区间逆序对了!Bakser神犇决定再考验一下他,他说道:
“在Gty的妹子序列里,某个妹子的美丽度可也是会变化的呢。你还能求出某个区间中妹子们美丽度的逆序对数吗?当然,为了方便,这次我们规定妹子们的美丽度在[1,n]中。仍然强制在线。”
Autumn需要你的帮助。
给定一个正整数序列a(1<=ai<=n),支持单点修改,对于每次询问,输出al...ar中的逆序对数,强制在线。

Input

第一行包括一个整数n(1<=n<=50000),表示数列a中的元素数。
第二行包括n个整数a1...an(1<=ai<=n)。
接下来一行包括一个整数m(1<=m<=50000),表示操作的个数。
接下来m行,每行包括3个整数。
0 L R (1<=L<=R<=n) 询问[L,R]中的逆序对数。
1 p v (1<=p<=n,1<=v<=n) 将p位置的数修改为v。
L,R,p,v 都需要异或上一次的答案,保证异或之后的值是合法的。
保证涉及的所有数在int内。

Output

对每个询问,单独输出一行,表示al...ar中的逆序对数。对每个询问,单独输出一行,表示al...ar中的逆序对数。

Sample Input

10
1 7 5 6 9 4 9 4 4 7
10
0 4 6
0 5 8
0 1 10
1 25 19
0 19 25
1 14 4
0 12 12
0 2 5
1 8 7
1 1 10

Sample Output

2
3
16
13
0
2

Solution

分块,同时维护几个数组:

$f[i]$表示第$i$块内部的逆序对个数。

$g[i][j]$表示第$i$块和第$j$块能形成的逆序对个数,第二维用树状数组维护。

$s[i][j]$表示前$i$块里$j$数出现的次数,第二维同样用树状数组维护。

查询就利用这三个数组查一下,利用好树状数组前缀和的性质。乱七八糟加加减减。

修改就维护好这三个数组就好了……

速度倒数第二$46s$低空飞过……心情简单……

Code

  1 #include<iostream>
  2 #include<cstring>
  3 #include<cstdio>
  4 #include<cmath>
  5 #define N (50009)
  6 #define S (259)
  7 using namespace std;
  8 
  9 int n,m,opt,l,r,ans,num,f[S],a[N];
 10 int ID[N],L[S],R[S];
 11 
 12 inline int read()
 13 {
 14     int x=0,w=1; char c=getchar();
 15     while (c<'0' || c>'9') {if (c=='-') w=-1; c=getchar();}
 16     while (c>='0' && c<='9') x=x*10+c-'0', c=getchar();
 17     return x*w;
 18 }
 19 
 20 struct BIT
 21 {
 22     int c[N];
 23     void Update(int x,int v)
 24     {
 25         for (; x<=n; c[x]+=v,x+=(x&-x));
 26     }
 27     int Query(int x)
 28     {
 29         int ans=0;
 30         for (; x; ans+=c[x],x-=(x&-x));
 31         return ans;
 32     }
 33 }B,g[S],s[S];
 34 
 35 void Build()
 36 {
 37     int unit=sqrt(n);
 38     num=n/unit+(n%unit!=0);
 39     for (int i=1; i<=num; ++i)
 40         L[i]=(i-1)*unit+1, R[i]=i*unit;
 41     R[num]=n;
 42     for (int i=1; i<=num; ++i)
 43         for (int j=L[i]; j<=R[i]; ++j) ID[j]=i;
 44 }
 45 
 46 void Preprocess()
 47 {
 48     for (int i=1; i<=num; ++i)
 49     {
 50         for (int j=L[i]; j<=R[i]; ++j)
 51         {
 52             f[i]+=B.Query(n)-B.Query(a[j]);
 53             B.Update(a[j],1);
 54         }
 55         for (int j=L[i]; j<=R[i]; ++j) B.Update(a[j],-1);
 56     }
 57     for (int i=2; i<=num; ++i)
 58         for (int j=1; j<=i-1; ++j)
 59         {
 60             for (int k=L[j]; k<=R[j]; ++k) B.Update(a[k],1);
 61             for (int k=L[i]; k<=R[i]; ++k) g[i].Update(j,B.Query(n)-B.Query(a[k]));
 62             for (int k=L[j]; k<=R[j]; ++k) B.Update(a[k],-1);
 63         }
 64     for (int i=1; i<=num; ++i)
 65         for (int j=L[i]; j<=R[i]; ++j) s[i].Update(a[j],1);
 66     for (int i=2; i<=num; ++i)
 67         for (int j=1; j<=n; ++j) s[i].Update(j,s[i-1].Query(j)-s[i-1].Query(j-1));
 68 }
 69 
 70 int Calc(int l,int r)
 71 {
 72     int ans=0;
 73     if (ID[l]==ID[r])
 74     {
 75         for (int i=l; i<=r; ++i)
 76         {
 77             ans+=B.Query(n)-B.Query(a[i]);
 78             B.Update(a[i],1);
 79         }
 80         for (int i=l; i<=r; ++i) B.Update(a[i],-1);
 81         return ans;
 82     }
 83     for (int i=l; i<=R[ID[l]]; ++i)
 84     {
 85         ans+=s[ID[r]-1].Query(a[i]-1)-s[ID[l]].Query(a[i]-1);
 86         ans+=B.Query(n)-B.Query(a[i]);
 87         B.Update(a[i],1);
 88     }
 89     for (int i=l; i<=R[ID[l]]; ++i) B.Update(a[i],-1);
 90     
 91     for (int i=L[ID[r]]; i<=r; ++i)
 92     {
 93         ans+=(s[ID[r]-1].Query(n)-s[ID[r]-1].Query(a[i]))-(s[ID[l]].Query(n)-s[ID[l]].Query(a[i]));
 94         ans+=B.Query(n)-B.Query(a[i]);
 95         B.Update(a[i],1);
 96     }
 97     for (int i=L[ID[r]]; i<=r; ++i) B.Update(a[i],-1);
 98     
 99     for (int i=ID[l]+1; i<=ID[r]-1; ++i) ans+=f[i];
100     for (int i=ID[l]+2; i<=ID[r]-1; ++i)
101         ans+=g[i].Query(i-1)-g[i].Query(ID[l]);
102     for (int i=l; i<=R[ID[l]]; ++i) B.Update(a[i],1);
103     for (int i=L[ID[r]]; i<=r; ++i) ans+=B.Query(n)-B.Query(a[i]);
104     for (int i=l; i<=R[ID[l]]; ++i) B.Update(a[i],-1);
105     return ans;
106 }
107 
108 void Change(int x,int k)
109 {
110     int id=ID[x];
111     for (int i=id; i<=num; ++i) s[i].Update(a[x],-1);
112     for (int i=id; i<=num; ++i) s[i].Update(k,1);
113     
114     for (int i=1; i<=id-1; ++i)
115     {
116         g[id].Update(i,-s[i].Query(n)+s[i].Query(a[x])+s[i-1].Query(n)-s[i-1].Query(a[x]));
117         g[id].Update(i,s[i].Query(n)-s[i].Query(k)-s[i-1].Query(n)+s[i-1].Query(k));
118     }
119     for (int i=id+1; i<=num; ++i)
120     {
121         g[i].Update(id,-s[i].Query(a[x]-1)+s[i-1].Query(a[x]-1));
122         g[i].Update(id,s[i].Query(k-1)-s[i-1].Query(k-1));
123     }
124     
125     f[id]=0; a[x]=k;
126     for (int i=L[id]; i<=R[id]; ++i)
127     {
128         f[id]+=B.Query(n)-B.Query(a[i]);
129         B.Update(a[i],1);
130     }
131     for (int i=L[id]; i<=R[id]; ++i) B.Update(a[i],-1);
132 }
133 
134 int main()
135 {
136     n=read();
137     Build();
138     for (int i=1; i<=n; ++i) a[i]=read();
139     Preprocess();
140     m=read();
141     while (m--)
142     {
143         opt=read(); l=read(); r=read();
144         l^=ans; r^=ans;
145         if (opt==0) printf("%d\n",ans=Calc(l,r));
146         else Change(l,r);
147     }
148 }
posted @ 2019-02-12 20:28  Refun  阅读(250)  评论(0编辑  收藏  举报