[bzoj3295] [Cqoi2011]动态逆序对

  数据似乎对不会cdq分治的选手极其不友好?。。。。。没错说的就是我这种上来就写树套树的傻逼>_<

  先求出逆序对数,每次删除时,假设要删掉数v,v在数列中的位置为pos。那么删除后将会减少(位置在pos之前的数比v大的个数 + 位置在pos之后的数比v小的个数)个逆序对。。。挺显然的。

  那就是树套树模板题了。。。然而我一开始写zkw线段树套treap,结果TLE了若干发。。毕竟数据范围10w。。。。

  事实上,用树状数组套treap就可以过。。虽然有点卡时限?

  然而我决定写发递归建树来爽爽。。其实就是把区间内的数排序好后,就可以O(n)建treap了(n是区间内数的个数

  具体实现的话就用归并排序。。。虽然说每次直接快排复杂度也不会很高(等等我好像不会算),但是用递归排序的话就能O(nlogn)建好整个树套树了。。

  然而总的时间复杂度还是O(mlog²n)= =。。。不过填了建树时间开销这个大坑

  最后5s+跑完(还是很慢>_<

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #define ll long long
 5 using namespace std;
 6 const int maxn=100023;
 7 int rt[262333],size,L[262333],R[262333];
 8 int sz[maxn*19],lc[maxn*19],rc[maxn*19],num[maxn*19],tot;
 9 bool w[maxn*19];
10 int tmp[maxn],mp[maxn],sm[maxn],pos[maxn];
11 int i,j,n,m,k,sum;
12 ll ans;
13 
14 int ra;char rx;
15 inline int read(){
16     rx=getchar(),ra=0;
17     while(rx<'0'||rx>'9')rx=getchar();
18     while(rx>='0'&&rx<='9')ra*=10,ra+=rx-48,rx=getchar();return ra;
19 }
20 //-----------------
21 inline void ins(int &x,int l,int r){
22     if(l>r)return;
23     x=++tot;
24     int mid=(l+r)>>1;num[x]=mp[mid],sz[x]=r-l+1,w[x]=1;
25     if(l<r)ins(lc[x],l,mid-1),ins(rc[x],mid+1,r);
26 }
27 inline void del(int x,int v){
28     sz[x]--;
29     if(v<num[x])del(lc[x],v);else
30     if(v>num[x])del(rc[x],v);else w[x]=0;
31 }
32 inline void qmx(int x,int v){
33     while(x)
34         if(v<num[x])sum+=sz[rc[x]]+w[x],x=lc[x];
35         else
36         if(v>num[x])x=rc[x];
37         else{
38             sum+=sz[rc[x]];break;
39         }
40 }
41 inline void qmn(int x,int v){
42     while(x)
43         if(v<num[x])x=lc[x];
44         else
45         if(v>num[x])sum+=sz[lc[x]]+w[x],x=rc[x];
46         else{
47             sum+=sz[lc[x]];break;
48         }
49 }
50 //----------------------
51 inline int min(int a,int b){return a<b?a:b;}
52 inline int max(int a,int b){return a<b?b:a;}
53 inline void build(){
54     register int ii,i,j,l,r,mid,sz;
55     for(i=n+size;i>size;i--)L[i]=R[i]=i-size,ins(rt[i],L[i],R[i]);
56     for(i=size<<1|1;i>n+size;i--)L[i]=n+1,R[i]=0;
57     for(ii=size;ii;ii--){
58         if(!R[ii<<1|1])
59             if(!R[ii<<1]){L[ii]=n+1,R[ii]=0;continue;}
60             else ins(rt[ii],L[ii<<1],R[ii<<1]),L[ii]=L[ii<<1],R[ii]=R[ii<<1];
61         else{
62             for(i=l=L[ii<<1],mid=R[ii<<1],j=mid+1,r=R[ii<<1|1],sz=i-1;i<=mid&&j<=r;)
63                 tmp[++sz]=mp[i]<mp[j]?mp[i++]:mp[j++];
64             while(i<=mid)tmp[++sz]=mp[i++];
65             while(j<=r)tmp[++sz]=mp[j++];
66             for(i=l;i<=r;i++)mp[i]=tmp[i];//归并排序
67             L[ii]=l,R[ii]=r,ins(rt[ii],L[ii],R[ii]);
68         }/原谅我乱用变量名>_<
69     }
70 }
71 inline void run(int v){
72     int x=pos[v],y;sum=0;
73     if(x>1)
74         for(y=x-1+size,qmx(rt[y],v);y>1;y>>=1)
75         if(y&1)qmx(rt[y^1],v);
76     if(x<n)
77         for(y=x+1+size,qmn(rt[y],v);y>1;y>>=1)
78         if(!(y&1))qmn(rt[y^1],v);
79     ans-=sum;
80     for(y=x+size;y;y>>=1)del(rt[y],v);
81 }
82 
83 int main(){
84     n=read(),m=read();
85     for(size=1;size<n;size<<=1);size--;
86     for(i=1;i<=n;i++){
87         for(pos[j=mp[i]=read()]=i;j<=n;j+=j&(-j))ans+=sm[j];
88         for(j=mp[i];j;j-=j&(-j))sm[j]++;
89     }
90     build();
91     while(m--){
92         printf("%lld\n",ans),j=read();
93         if(m)run(j);
94     }
95     return 0;
96 }
View Code

 

你可能感兴趣的:([bzoj3295] [Cqoi2011]动态逆序对)