• BZOJ3295 动态逆序对 树套树, 树状数组套线段树(主席树)


        Orz黄学长,蒟蒻在黄学长的带领下,通过阅读黄学长的代码!终于会了这道题! 首先我想先说一下这道题的思路(准确来说是黄学长的)。 很明显,树状数组应该不用讲吧!关键是内存怎么开,维护一些什么样的数据? 其实我们通过观察,很快可以发现,你维护被删的数比维护所有的数轻松多了(不管是空间上,还是时间上)。所以我们就可以从这方面想!(其实我一开始的思路,因为这道题我已经看过很久了,一直想写,毕竟是白书里面的一道例题嘛!一开始,蒟蒻的我是打算这样的用树状数组套权值线段树,并且是维护所有的数,我发现空间不够我开的(或许是我太弱,有大神的话请指教一下。)。好像是因为我维护所有的数才错了,(而且就算要维护,也是动态开点第维护)仔细一想黄学长就是树状数组套权值线段树啊!太弱了我啊!too young too simple 。而且宝宝,开点的时候,一开始只开了一百万,WA掉了,后来看了黄学长开了五百万,自己再仔细一想,logN = 17 , 因为是树套树所以是 logN的平方, 还要乘上操作的次数M, 所以………………,我又错了。加油了多积累经验)。

    这是黄学长的树状数组套权值线段树(当然,为了不当简单的做一条源程狗,我自己敲了一遍,并做了修改)

      1 #include<cstdio>
      2 #include<iostream>
      3 #include<cstring>
      4 #define rep(i,j,k) for(int i = j; i <= k; i++)
      5 #define down(i,j,k) for(int i = j; i >= k; i--)
      6 #define lc c[k][0]
      7 #define rc c[k][1]
      8 #define N 5000005
      9 #define ll long long
     10 #define maxn 102333
     11 using namespace std;
     12 
     13 int t[maxn], c[N][2], root[maxn], sum[N], a1[maxn], a2[maxn], pos[maxn], num[maxn];  
     14 int A[30], B[30]; 
     15 
     16 int cnt = 0, n, m;
     17 int read()
     18 {
     19     int s = 0, t = 1; char c = getchar();
     20     while( !isdigit(c) ){
     21         if( c == '-' ) t = -1; c = getchar();
     22     }
     23     while( isdigit(c) ){
     24         s = s * 10 + c - '0'; c = getchar();
     25     }
     26     return s * t;
     27 }
     28 int lower(int x) {return x & (-x); }
     29 
     30 int get_num(int x)
     31 {
     32     int ans = 0;
     33     for( ; x; x -= lower(x))  ans += t[x];
     34     return ans;
     35 }
     36 
     37 void update(int&k,int l,int r,int num)
     38 {
     39     if( !k ) k = ++cnt;
     40     sum[k]++;
     41     if( l == r ) return;
     42     int mid = (l+r)>>1;
     43     if( mid < num ) update(rc,mid+1,r,num);
     44     else update(lc,l,mid,num); 
     45 }
     46 
     47 ll get_more(int x,int y,int num)
     48 {
     49     A[0] = B[0] = 0; x--; ll tmp = 0;
     50     for( ; x; x -= lower(x) ) A[++A[0]] = root[x];
     51     for( ; y; y -= lower(y) ) B[++B[0]] = root[y];
     52     int l = 1, r = n;
     53     while( l != r ){
     54         int mid = (l+r)>>1;
     55         if( num <= mid ) {
     56             rep(i,1,A[0]) tmp -= sum[c[A[i]][1]];
     57             rep(i,1,B[0]) tmp += sum[c[B[i]][1]];
     58             rep(i,1,A[0]) A[i] = c[A[i]][0];
     59             rep(i,1,B[0]) B[i] = c[B[i]][0];
     60             r = mid;
     61         }
     62         else {
     63             rep(i,1,A[0]) A[i] = c[A[i]][1];
     64             rep(i,1,B[0]) B[i] = c[B[i]][1];
     65             l = mid+1;
     66         }
     67     }
     68     return tmp;
     69 }
     70 
     71 ll get_less(int x,int y,int num)
     72 {
     73     A[0] = B[0] = 0; x--; ll tmp = 0;
     74     for( ; x; x -= lower(x)) A[++A[0]] = root[x];
     75     for( ; y; y -= lower(y)) B[++B[0]] = root[y];
     76     int l = 1, r = n;
     77     while( l != r ){
     78         int mid = (l+r)>>1;
     79         if( num > mid ){
     80             rep(i,1,A[0]) tmp -= sum[c[A[i]][0]];
     81             rep(i,1,B[0]) tmp += sum[c[B[i]][0]];
     82             rep(i,1,A[0]) A[i] = c[A[i]][1];
     83             rep(i,1,B[0]) B[i] = c[B[i]][1];
     84             l = mid + 1;
     85         }
     86         else {
     87             rep(i,1,A[0]) A[i] = c[A[i]][0];
     88             rep(i,1,B[0]) B[i] = c[B[i]][0];
     89             r = mid;
     90         }
     91     }
     92     return tmp;
     93 }
     94 
     95 int main()
     96 {
     97     n = read(), m = read(); ll ans = 0;
     98     rep(i,1,n){
     99         num[i] = read(); pos[num[i]] = i;   
    100         a1[i] = get_num(n)-get_num(num[i]-1);
    101         ans += a1[i];
    102         for(int x = num[i]; x <= n; x += lower(x) ) t[x]++;
    103     }
    104     memset(t,0,sizeof(t));
    105     down(i,n,1){
    106         int x = num[i];
    107         a2[i] = get_num(x-1);
    108         for( ; x <= n; x += lower(x) ) t[x]++;
    109     }
    110     rep(i,1,m){
    111         printf("%lld
    ", ans);
    112         int x = read(); int po = pos[x];
    113         ans -= (a1[po] + a2[po] - get_more(1,po-1,x) - get_less(po+1,n,x));
    114         for( ; po <= n; po += lower(po) ) update(root[po],1,n,x);
    115     } 
    116     return 0;
    117 }

    据翻博客,有人分块A掉了,我不信,怎么可能呢?可是这怎么知道呢?还是还要敲的。很明显,以比树套树的代码慢一倍的代价(大约),A掉了。哈哈!到现在好像还真的没怎么看过分块A不掉的题(不过肯定是有的,是蒟蒻写的题太少,蒟蒻写的题分块几乎都能写),但是写这个不利于自身水平的提高啊!(不到迫不得已,还是少写分块吧!)

     1 #include<vector>
     2 #include<iostream>
     3 #include<cstdio>
     4 #include<algorithm>
     5 #include<cstring>
     6 #define ll long long
     7 #define rep(i,j,k) for(int i = j; i <= k; i++)
     8 #define down(i,j,k) for(int i = j; i >= k; i--)
     9 #define maxn 323
    10 #define inf 0x7fffffff
    11 using namespace std;
    12 
    13 vector<int> s[maxn];
    14 int pos[100233], v[100233], t[100233];
    15 bool vis[100233];
    16 int n, m;
    17 
    18 int lower(int x ) { return x & (-x); }
    19 int getans(int x)
    20 {
    21     int ans = 0; for(; x; x -= lower(x) ) ans += t[x];
    22     return ans;
    23 }
    24 
    25 int read()
    26 {
    27     int s = 0, t = 1; char c = getchar();
    28     while( !isdigit(c) ){
    29         if( c == '-' ) t = -1; c = getchar();
    30     }
    31     while( isdigit(c) ){
    32         s = s * 10 + c - '0'; c = getchar();
    33     }
    34     return s * t;
    35 }
    36 
    37 int get_max(int r,int num)
    38 {
    39     int last = r / maxn; int tmp = 0;
    40     rep(i,0,last-1) {
    41         tmp += (s[i].size()-1-(upper_bound(s[i].begin(),s[i].end(),num)-s[i].begin()));
    42     }
    43     int begin = last*maxn;
    44     rep(i,begin,r){
    45         if( !vis[i] && v[i] > num ) tmp++;
    46     }
    47     //cout<<" a "<<tmp<<" ";
    48     return tmp;
    49 }
    50 
    51 int get_min(int l,int num)
    52 {
    53     int begin = l / maxn; int tmp = 0;
    54     rep(i,begin+1,n/maxn){
    55         tmp += (lower_bound(s[i].begin(),s[i].end(),num)-s[i].begin());
    56     }
    57     int last = (begin+1)*maxn-1;
    58     rep(i,l,min(last,n)){
    59     //    cout<<l+1<<" "<<last<<endl; 
    60     //        cout<<"k "<<i<<endl;
    61         if( !vis[i] && v[i] < num ) tmp++;
    62     } 
    63 //    cout<<" i "<<tmp<<" ";
    64     return tmp;
    65 }
    66 
    67 void update(int pos,int num)
    68 {
    69     int x = pos / maxn;
    70 //    cout<<"U "<<pos<<endl;
    71     s[x].erase(lower_bound(s[x].begin(),s[x].end(),num));
    72     vis[pos] = 1;
    73 }
    74 
    75 int main()
    76 {
    77     n = read(), m = read(); ll ans = 0;
    78     rep(i,0,maxn) s[i].push_back(inf); 
    79     rep(i,1,n){
    80         v[i] = read(); pos[v[i]] = i; s[i/maxn].insert(lower_bound(s[i/maxn].begin(),s[i/maxn].end(),v[i]),v[i]);
    81         ans += (getans(n)-getans(v[i]-1));
    82         for(int x = v[i]; x <= n ; x += lower(x) ) t[x]++;
    83     }
    84     memset(t,0,sizeof(t));
    85     rep(i,1,m){
    86         printf("%lld
    ", ans);
    87         int x = read(), po = pos[x];
    88         ans -= (get_max(po-1,x)+get_min(po+1,x));
    89         update(po,x);
    90         //cout<<endl;
    91     }
    92     return 0;
    93 }

    据说此题还有 cdq分治写法,我也orz一下。(这个明天再写了)

  • 相关阅读:
    phpcms 栏目图片循环调用
    phpcms调栏目图片
    Java 面向对象 --单例模式
    Java 面向对象 --包装类
    Java 面向对象 --匿名内部类
    Java面向对象--instanceof关键字
    Java 面向对象 --Object类
    Java 面向对象 --多态性
    Java 面向对象 --接口
    Java 面向对象 --抽象类
  • 原文地址:https://www.cnblogs.com/83131yyl/p/5131720.html
Copyright © 2020-2023  润新知