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 }

 

posted @ 2018-03-22 15:25  CHerish_OI  阅读(203)  评论(0编辑  收藏  举报