bzoj3295: [Cqoi2011]动态逆序对(cdq分治+树状数组)
3295: [Cqoi2011]动态逆序对
题目:传送门
题解:
刚学完cdq分治,想起来之前有一道是树套树的题目可以用cdq分治来做...尝试一波
还是太弱了...想到了要做两次cdq...然后伏地膜大佬
其实需要维护的地方还是很容易想到的:
第一维维护位置w,第二维维护数值s,第三维维护修改的时间t。
那么对于t我们可以倒序插入,然后我们就可以把它看作t从小到大的插入结点(即使没有删除的点为了方便也要更新一下t)。
再去观察就会发现,当我们插入一个节点t0时,我们需要求的就是在t0左边的比它大的数和在右边比它小的数:
t<t0 w<w0 s>s0
t<t0 w>w0 s<s0
再转化一下符号:
t<t0 w<w0 s<(n-s0+1)
t<t0 w<(n-w0+1) s<s0
这时候再看,不就是陌上花开吗!!!
ps:大佬实在是太强了,记得开longlong(虽然不是很懂为什么,但是就是错了...)
代码:
1 #include<cstdio> 2 #include<cstring> 3 #include<cstdlib> 4 #include<cmath> 5 #include<algorithm> 6 using namespace std; 7 typedef long long LL; 8 struct node 9 { 10 int w,s,t;//位置,数值,操作时间 11 LL ans;//当前时间的答案 12 }a[110000],ba[110000];int n,m,b[110000];LL ans[110000]; 13 bool cmp(node n1,node n2){return n1.t<n2.t;} 14 LL s[110000]; 15 int lowbit(int x){return x&-x;} 16 void add(int x,int k){while(x<=n){s[x]+=k;x+=lowbit(x);}} 17 int getsum(int x){LL ans=0;while(x){ans+=s[x];x-=lowbit(x);}return ans;} 18 void cdq(int l,int r) 19 { 20 if(l==r)return ; 21 int mid=(l+r)>>1; 22 cdq(l,mid);cdq(mid+1,r); 23 int i=l,j=mid+1,p=l; 24 while(i<=mid && j<=r) 25 { 26 if(a[i].w<a[j].w) 27 { 28 add(a[i].s,1); 29 ba[p++]=a[i++]; 30 } 31 else 32 { 33 a[j].ans+=getsum(a[j].s); 34 ba[p++]=a[j++]; 35 } 36 } 37 while(i<=mid)add(a[i].s,1),ba[p++]=a[i++]; 38 while(j<=r)a[j].ans+=getsum(a[j].s),ba[p++]=a[j++]; 39 40 for(int i=l;i<=mid;i++)add(a[i].s,-1); 41 42 for(int i=l;i<=r;i++)a[i]=ba[i]; 43 } 44 int main() 45 { 46 scanf("%d%d",&n,&m);int x,cc=n; 47 for(int i=1;i<=n;i++)a[i].w=i,scanf("%d",&a[i].s); 48 for(int i=1;i<=m;i++)scanf("%d",&x),b[x]=i;int s=m; 49 for(int i=1;i<=n;i++)if(!b[i])b[i]=++s; 50 for(int i=1;i<=n;i++)a[i].t=n-b[a[i].s]+1; 51 sort(a+1,a+n+1,cmp); 52 for(int i=1;i<=n;i++)a[i].s=n-a[i].s+1; 53 cdq(1,n); 54 sort(a+1,a+n+1,cmp); 55 for(int i=1;i<=n;i++) 56 { 57 a[i].s=n-a[i].s+1; 58 a[i].w=n-a[i].w+1; 59 } 60 cdq(1,n); 61 for(int i=1;i<=n;i++)ans[a[i].t]=a[i].ans; 62 for(int i=1;i<=n;i++)ans[i]+=ans[i-1]; 63 for(int i=n;i>=n-m+1;i--)printf("%lld\n",ans[i]); 64 return 0; 65 }