zoukankan      html  css  js  c++  java
  • 【Bzoj 3295】 动态逆序对(树套树|CDQ分治)

    【题意】

      每次删除一个数,然后问删除前逆序对数。

    【分析】

      没有AC不开心。。

      我的树状数组套字母树,应该是爆空间的,空间复杂度O(nlogn^2)啊。。哭。。

      然后就没有然后了,别人家的树套树是树状数组套平衡树,O(nlogn)的啊。。

      别人家的CDQ分治更屌。。我垃圾咯。

    只是存个代码:

      1 #include<cstdio>
      2 #include<cstdlib>
      3 #include<cstring>
      4 #include<iostream>
      5 #include<algorithm>
      6 #include<queue>
      7 using namespace std;
      8 #define Maxn 200010
      9 #define Maxd 31
     10 
     11 int a[Maxn],wr[Maxn];
     12 int n,m;
     13 
     14 struct node
     15 {
     16     int son[2],cnt;
     17 }tr[Maxn*10*20];int tot;
     18 
     19 void upd(int x)
     20 {
     21     tr[x].son[0]=tr[x].son[1]=0;
     22     tr[x].cnt=0;
     23 }
     24 
     25 void add(int now,int y,int c)
     26 {
     27     for(int i=Maxd;i>=1;i--)
     28     {
     29         int ind=y>>i-1;
     30         y=y%(1<<i-1);
     31         if(!tr[now].son[ind])
     32         {
     33             tr[now].son[ind]=++tot;
     34             upd(tot);
     35         }
     36         now=tr[now].son[ind];
     37         tr[now].cnt+=c;
     38     }
     39 }
     40 
     41 int ffind(int now,int y)
     42 {
     43     int ans=0;
     44     for(int i=Maxd;i>=1;i--)
     45     {
     46         int ind=y>>i-1;
     47         y=y%(1<<i-1);
     48         if(ind==0)
     49         {
     50             ans+=tr[tr[now].son[1]].cnt;
     51             now=tr[now].son[0];
     52         }
     53         else now=tr[now].son[1];
     54     }
     55     return ans;
     56 }
     57 
     58 int sm[Maxn];
     59 void change(int x,int y,int c)
     60 {
     61     for(int i=x;i<=n;i+=i&(-i))
     62         add(i,y,c),sm[i]+=c;
     63     
     64 }
     65 
     66 int ad;
     67 int query(int x,int y)
     68 {
     69     ad=0;
     70     int ans=0;
     71     for(int i=x;i>=1;i-=i&(-i))
     72         ad+=sm[i],ans+=ffind(i,y);
     73     return ans;
     74 }
     75 
     76 int main()
     77 {
     78     int ans=0;
     79     scanf("%d%d",&n,&m);
     80     memset(sm,0,sizeof(sm));
     81     for(int i=1;i<=n;i++) {scanf("%d",&a[i]);wr[a[i]]=i;}
     82     upd(0);
     83     tot=n;
     84     for(int i=1;i<=n;i++)
     85     {
     86         ans+=query(i-1,a[i]);
     87         change(i,a[i],1);
     88     }
     89     int sum=n;
     90     for(int i=1;i<=m;i++)
     91     {
     92         int x;
     93         scanf("%d",&x);
     94         printf("%d
    ",ans);
     95         sum--;
     96         change(wr[x],x,-1);
     97         int now=-query(n,x);
     98         now+=2*query(wr[x]-1,x);
     99         ans-=sum+now-ad;
    100     }
    101     return 0; 
    102 
    103 }
    View Code

    2016-11-08 16:42:22


    学了cdq分治回来更新耶!!

    用CDQ分治AC啦哈哈~~

    CDQ分治比树套树省空间多了,空间是O(n)的,时间还是O(nlogn^2)

    然后,简单说一下?

    我自己也不是很懂,刚会。。

    Solve(l,r)为求出区间l~r的答案。

    然后只有编号小于它的对他有影响。

    然后二分 [l,mid]和[mid+1,r],,考虑完[l,mid]对[mid+1,r]的影响之后,那两个区间就可以分开搞了。(就是分治)

    问题变成快速求[l,mid]对[mid+1,r]的影响。

    本题中,我们可以看成是一个三元组i->(xi,yi,zi),然后ans[i]=x<xi y<yi z>zi或者x<xi y>yi z<zi 的数量。。

    x这一维是时间戳,y是编号,z是值(想一想就知道他为什么表示逆序对啦!!!)

    那么,只有x<xi的对xi有影响,把x这一维作为编号。

    快速求出,[l,mid]对[mid+1,r]中y<yi z>zi或者y>yi z<zi 的数量

    可以用y排序,树状数组维护,求和,就知道y和z的逆序对数了。。

    n元组,满足x>xi,y>yi....的个数的东东 。。【这东西叫n维偏序???好像是CDQ分治的经典题哦!!

    啊。。。WA了好久,竟然是没有开LL!!!!好傻啊、、

      1 #include<cstdio>
      2 #include<cstdlib>
      3 #include<cstring>
      4 #include<iostream>
      5 #include<algorithm>
      6 #include<queue>
      7 using namespace std;
      8 #define Maxn 200010
      9 #define LL long long
     10 
     11 int a[Maxn],b[Maxn];
     12 LL f[Maxn];
     13 int n,m;
     14 
     15 int c[Maxn];
     16 bool vis[Maxn];
     17 
     18 struct node
     19 {
     20     int x,y,id;
     21 }t[Maxn];int tl;
     22 
     23 int mymax(int x,int y) {return x>y?x:y;}
     24 bool cmp(node x,node y) {return x.x>y.x;}
     25 bool cmp2(node x,node y) {return x.x<y.x;}
     26 
     27 void add(int x,int y)
     28 {
     29     for(int i=x;i<=n;i+=i&(-i))
     30         c[i]+=y;
     31 }
     32 
     33 int query(int x)
     34 {
     35     int ans=0;
     36     for(int i=x;i>=1;i-=i&(-i))
     37         ans+=c[i];
     38     return ans;
     39 }
     40 
     41 void solve2(int l,int r)
     42 {
     43     tl=0;
     44     for(int i=l;i<=r;i++)
     45     {
     46         t[++tl].x=a[i];
     47         t[tl].y=b[i];
     48         t[tl].id=i;
     49     }
     50     sort(t+1,t+1+tl,cmp);
     51     for(int i=1;i<=tl;i++)
     52     {
     53         if(vis[t[i].id]) f[t[i].id]+=query(t[i].y);
     54         else add(t[i].y,1);
     55     }
     56     for(int i=1;i<=tl;i++) if(!vis[t[i].id]) add(t[i].y,-1);
     57     sort(t+1,t+1+tl,cmp2);
     58     for(int i=1;i<=tl;i++)
     59     {
     60         if(vis[t[i].id]) f[t[i].id]+=query(n-t[i].y+1);
     61         else add(n-t[i].y+1,1);
     62     }
     63     for(int i=1;i<=tl;i++) if(!vis[t[i].id]) add(n-t[i].y+1,-1);
     64 }
     65 
     66 void solve(int l,int r)
     67 {
     68     if(l==r) return;
     69     int mid=(l+r)>>1;
     70     for(int i=l;i<=mid;i++) vis[i]=0;
     71     for(int i=mid+1;i<=r;i++) vis[i]=1;
     72     solve2(l,r);
     73     solve(l,mid);solve(mid+1,r);
     74 }
     75 
     76 int wr[Maxn],d[Maxn];
     77 void init()
     78 {
     79     scanf("%d%d",&n,&m);
     80     for(int i=1;i<=n;i++) 
     81     {
     82         int x;
     83         scanf("%d",&x);
     84         wr[x]=i;
     85     }
     86     for(int i=n;i>n-m;i--)
     87     {
     88         int x;
     89         scanf("%d",&x);
     90         a[i]=x;
     91         b[i]=wr[x];
     92         wr[x]=0;
     93     }
     94     int now=n-m+1;
     95     for(int i=1;i<=n;i++) if(wr[i]!=0) a[--now]=i,b[now]=wr[i];
     96     memset(c,0,sizeof(c));
     97     memset(f,0,sizeof(f));
     98 }
     99 
    100 int main()
    101 {
    102     init();
    103     solve(1,n);
    104     LL ans=0;
    105     for(int i=1;i<=n;i++) ans+=f[i];
    106     for(int i=n;i>n-m;i--)
    107     {
    108         printf("%lld
    ",ans);
    109         ans-=f[i];
    110     }
    111     return 0;
    112 }
    View Code

    代码还不是很长啦,主要是CDQ分治空间真的要小很多。。

    所以才知道,为什么大神说树套树粉转路人了ORZ。。。

    2016-11-08 20:14:57

  • 相关阅读:
    Linux学习 :字符设备框架
    Linux学习 :Uboot, Kernel, 根文件系统初步分析
    Linux学习 : 裸板调试 之 配置UART
    Linux学习 : 裸板调试 之 配置使用NAND FLASH
    Linux学习 : 裸板调试 之 使用MMU
    Linux I2C总线控制器驱动(S3C2440)
    Linux I2C总线设备驱动模型分析(ov7740)
    Linux摄像头驱动学习之:(六)UVC-基本框架代码分析
    【Java】 剑指offer(25) 合并两个排序的链表
    【Java】 剑指offer(24) 反转链表
  • 原文地址:https://www.cnblogs.com/Konjakmoyu/p/6043593.html
Copyright © 2011-2022 走看看