zoukankan      html  css  js  c++  java
  • 7.29集训

    上午

    (睡觉ing)

    主要也就是讲了数据结构

    讲了树状数组,线段树的相关操作(貌似没有提到分块)

    单改区查

    click

    秒切

    区改单查

    click

    搞个差分数组,还是切

    区改区查

    click

    推式子....

    p的前缀和=egin{aligned}sum_{i=1}^p a[i] = sum_{i=1}psum_{j=1}i d[j]end{aligned}

    其中d数组为差分数组

    在等式最右侧的式子(egin{aligned}sum_{i=1}^psum_{j=1}^id[j]end{aligned}) 中,(d[1])被利用了(p)次,(d[2])(被利用了)(p-1)次…….,因此我们可以推出

    p的前缀和= egin{aligned}sum_{i=1}psum_{j=1}id[j] = sum_{i=1}^pd[i]*(p-i+1)end{aligned}

    然后我们考虑将(p+1)(-i) 提出来

    p的前缀和=(egin{aligned}(p+1)*sum_{i=1}^pd[i]-sum_{i=1}^pd[i]*iend{aligned})

    那么我们考虑维护两个数组的前缀和:一个数组是(sum1[i] = d[i]),另一个是(sum2[i] = d[i]*i)

    查询的时候位置p的前缀和为:((p+1)*sum1)数组中p的前缀和-(sum2)数组中p的前缀和

    区间[(l,r])的和即:位置(r)的前缀和 - 位置(l-1)的前缀和。

    修改的时候对sum1数组正常差分

    (sum2)数组类似,对(sum2[i])加上(l*x),给(sum2[r+1])减去((r-1)*x)

    Code
    inline void jia (int x, int val) {
       for (int i = x; i <= n; i += lowbit(i))
          sum1[i] += val, sum2[i] += val*x;
    }
    inline void qujianjia (int l, int r, int val) {jia(l, val), jia(r+1, -val);}
    inline int chaxun(int x) {
       int res(0);
       for (int i = x; i; i -= lowbit(i))
          res += (x + 1)*sum1[i] - sum2[i];
       return res;
    }
    inline int qujianchaxun(int l, int r) {return chaxun(r) - chaxun(l-1);}
    

    逆序对

    click

    way1.我们可以用归并排序来求

    如果我们想将一个序列拍成有序的,那么每次合并的时候,左右两边的序列一定是有序的

    我们每次只需要考虑右边的数能与左边的数分别构成多少个逆序对

    看个例子左区间(a = left{5,6,7 ight})右区间 (b = left{1, 2, 9 ight})

    1. 5 > 1, 发现产生了逆序对, 此时做区间没有合并的数都要比1大,所以1与左边区间共产生了三个逆序对

    2. 5 > 2, 由上文可知产生了产生了三对逆序对

    ….

    所以:

    tot += (LL)mid - i + 1;
    

    复杂度(nlogn)

    way2.用树状数组当然是建立权值树状数组

    我们考虑逆序对的定义,首先是(i>j),其次是(a[i] < a[j])

    在树状数组里面,对于权值树状数组,我们肯定考虑离散化

    对于每次新进的数x,我们考虑在树状数组上在下标为x的地方加1,代表这个数存在过

    而我们再来思考逆序对的定义,说白了就是在当前这个数的前面,有多少个比ta大的

    求一遍(1) ~ (x)这个数的前缀和,再用一共输入的点的个数前去这部分,不就剩下了比x大的部分?

    PS:(rank[i])表示原序列中第(i)个数目前的排名(大小)是多少

    #include <bits/stdc++.h>
    #define int long long 
    #define lowbit(x) (x&-x)
    using namespace std;
    
    const int N = 5e5+66;
    
    int n, m, tot;
    int rank[N], tree[N];
    
    struct node {int val, id;}a[N];
    
    inline int cmp (node x, node y) {
       return (x.val<y.val)||(x.val == y.val && x.id < y.id);
    }
    
    inline void charu (int x, int val) {
       for (int i = x; i <= n; i += lowbit(i))
          tree[i] += val;
    }
    
    inline int chaxun (int x) {
       int res = 0;
       while (x) {
          res += tree[x];
          x -= lowbit(x);
       }
       return res;
    }
    
    signed main () {
       cin >> n;
       for (int i = 1; i <= n; ++ i) {
          cin >> a[i].val;
          a[i].id = i;
       }
       sort (a + 1, a + n + 1, cmp);
       for (int i = 1; i <= n; ++ i) rank[a[i].id] = i;
       for (int i = 1; i <= n; ++ i) {
          charu(rank[i], 1);
          tot += i-chaxun(rank[i]);
       }
       cout << tot;
       return 0;
    }
    

    小火柴

    click

    考虑,我们需要保证的是,a序列的第k大数对应着b序列中第k大的数

    所以在离散化完成后的数组内,我们假设(a = left{ 4,3,1,2 ight}),(b = left{ 1,3,2,4 ight})

    (q[a[i]] = b[i]),相当于以(a[i])为关键字对(b[i])进行排序

    得到(q[1] = 2, q[2] = 4, q[3] = 3, q[4] = 1),意味着,a中的1对应着b中的2,a中的2对应着b中的4

    若序列a与序列b相等,也就是说(q[i] = i)

    我们想让(a,b)序列相等,就要保证q数组单调递增

    所以原来问题转化为:将原来凌乱的q数组转化为一个升序数组需要的最小次数,且每一次只能交换相邻的两个数

    这不是逆序对这是啥?

    项链

    click

    (nlogn)离线树状数组才能做,莫队会被卡

    我们首先肯定要把询问按照右端点从小到大排序,这样保证我们不会来回跳转

    然后我们考虑当前这个颜色是否出现过,如果发现没有出现过,那么就令他为(1),如果出现过,就令前面出现的那次(+(-1)),这次为(1)

    此时我们考虑两种情况,

    第一种:上次出现的颜色在当前查询的区间内,那么我们新规定的颜色,完全可以取代上一次的,题目在询问我们有多少种颜色,并不在乎出现次数

    第二种,上次出现的颜色不在当前查询的区间内,那更好,我们之前的修改完毕之后,我们以后肯定不会再用它,因为我们的r是从前往后扫的

    每次查询的时候,我们就查询这个区间的l与r之间存在多少个1,利用树状数组可以很好的完成

    #include <bits/stdc++.h>
    // #define debug
    #define lowbit(x) (x&-x)
    using namespace std;
    
    const int N = 2e6+66;
    
    int n, m;
    int a[N], ans[N];
    int vis[N], tree[N];
    
    struct node {int l, r, id;}q[N];
    
    inline int cmp (node x, node y) {return x.r < y.r;}
    
    inline void charu (int x, int val) {
       for (int i = x; i <= n; i += lowbit(i))
          tree[i] += val;
    }
    
    inline int chaxun (int x) {
       int res = 0;
       while (x) {
          res += tree[x];
          x -= lowbit(x);
       }
       return res;
    }
    
    int main () {
       scanf ("%d", &n);
       for (int i = 1; i <= n; ++ i) scanf ("%d", &a[i]);
       scanf ("%d", &m);
       for (int i = 1; i <= m; ++ i) {
          int l, r;
          scanf ("%d%d", &q[i].l, &q[i].r);
          q[i].id = i;
       }
       sort(q+1, q+m+1, cmp);
       int now = 1;
       for (int i = 1; i <= n; ++ i) {
          if (!vis[a[i]]) {
    	 vis[a[i]] = i;
    	 charu(i, 1);
          } else {
             charu(vis[a[i]], -1);
             charu(i, 1);
             vis[a[i]] = i;
          }
          while (q[now].r == i) {
          	 ans[q[now].id] = chaxun(q[now].r) - chaxun(q[now].l-1);
    #ifdef debug
    cout << "now:-->" << now << '
    ';
    #endif 
             ++ now;
          }
       }
    #ifdef debug
    printf ("
    
    
    ");
    #endif 
       for (int i = 1; i <= m; ++ i) cout << ans[i] << '
    ';
       return 0;
    }
    

    异或和

    click

    题目是在求所有连续和的异或之和,即:(oplus sum_limits{i=1}^nsum_limits{j=0}^{i-1}sum(i)-sum(j))

    观察数据范围,(sum_limits{i=1}^{n}a[i] leq 1e6) --> 考虑前缀和

    考虑二进制下每一位对答案的影响,所以分四种情况

    设第一个数(A),第二个数为(B),所以分为(A=1)(B=1)(A=1)(B=0)的情况

    (1 - 1 = 1)

    说明第一个数的第(k)位为(1)的时候,前(k-1)位要比(B)的前(k-1)位小

    (1 - 0 = 1)

    说明第一个数的第(k)位为(1)的时候,前(k-1)位要比(B)的前(k-1)位大

    (0 - 1 = 0)

    说明第一个数的第(k)位为(0)的时候,前(k-1)位要比(B)的前(k-1)位小

    (0 - 1 = 1)

    说明第一个数的第(k)位为(0)的时候,前(k-1)位要比(B)的前(k-1)位大

    然后埋坑.....

    附近公园

    click

    先把这个序列大于等于水面的取为1,否则为0

    考虑每一位置对他左边的取一个min和max,考虑min与max序列中,“1”的那些位置有几个不一样

    就相当于存在了几对区间,所以

    ans = differt >> 1;
    

    然后我们考虑用min和max来围护一个什么东西,用离散化加树状数组就好

    关于可持久化线段树

    考虑对每一个状态都开一个线段树,为了使其优化,我们尝试当前树连之前树的边,这样会优化空间

    单点修改的话,可以简单一些

    对于区间修改的东西,我们得边读入边建树

    而对于可持久化权值线段树,也就是主席树(jmh树)

    我不会...

    不会就要学啊!等我回头补上!!!

    下午

    讲了一下午树剖,不懂..... click

    晚上

    写博客 补坑

  • 相关阅读:
    DIY组装机
    伯努利数学习笔记的说...
    心得分享 | 软件研发效能(1)
    开发板烧录教程
    解决Windows7/10系统连接网线后显示“未识别的网络”的问题
    雷达扫描
    经验学习
    1045 Access denied for user 'root'@'localhost' (using password:YES)
    json格式化工具
    mysql安装出现error Nr.1045
  • 原文地址:https://www.cnblogs.com/yszhyhm/p/13395418.html
Copyright © 2011-2022 走看看