• 差分思想+树状数组


      我们知道,基础的树状数组只能方便进行单点修改,若要进行区间修改,则树状数组就会有其劣势。所以,我们引入差分思想,来方便进行区间修改(毕竟树状数组还是比线段树好打得多QAQ)
      何为差分呢?
      现在我们有一个从小到大的数列a[]
      a 1 3 6 8 9
      然后还有一个差分数组b[]
      b 1 2 3 2 1
      相信某些小伙伴已经看出端倪了..这里b[i]=a[i]-a[i-1],我令a[0]=0,故b[1]=a[1]。
      拥有了b数组,我们就可以很简单的求出bit[]中任意一个数,只需bit[i]=sigma(k=1 to i) b[k](这个很好推吧..)
      我觉得现在该有人说我zz了..何必不直接查询a[i]而是找这么麻烦一个方法..这里我们转回正题!别忘了,题目要我们进行区间修改..
      我们知道,树状数组对于单点值的修改十分方便(不懂的去看树状数组1),对于区间的修改就比较尴尬..而我们又不想敲死长的线段树..怎么办呢,这时候差分就显出优势
      还是上面的a[]和b[],现在我们使区间[2,4]的所有数均+2,则a[]/b[]变为
      a 1 5 8 10 9
      b 1 4 3 2 -1
      事实上,这里只有b[2]和b[5]发生了变化,因为区间内元素均增加了同一个值,所以b[3],b[4]是不会变化的。
      这里我们就有了第二个式子:对于区间[x,y]的修改(增加值为d)在b数组内引起变化的只有 b[x]+=d,b[y+1]-=d。(这个也很好推的..)
      这样,我们就把树状数组的软肋用差分解决了

    下面来看两个题目:

    洛谷3368

    链接:https://www.luogu.org/problem/show?pid=3368

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 using namespace std;
     5 const int maxn=500000+10;
     6 int c[maxn];
     7 int n,m;
     8 int lowbit(int x){
     9     return x&(-x);
    10 }
    11 void add(int x,int d){
    12     while(x<=n){
    13         c[x]+=d;
    14         x+=lowbit(x);
    15     }
    16 }
    17 int sum(int x){
    18     int ret=0;
    19     while(x>0){
    20         ret+=c[x];
    21         x-=lowbit(x);
    22     }
    23     return ret;
    24 }
    25 int main(int argc, char const *argv[])
    26 {
    27     /* code */
    28     memset(c,0,sizeof(c));
    29     scanf("%d%d",&n,&m);
    30     int last=0;
    31     for(int i=1;i<=n;i++){
    32         int x;
    33         scanf("%d",&x);
    34         add(i,x-last);
    35         last=x;
    36     }
    37     while(m--){
    38         int num;
    39         scanf("%d",&num);
    40         if(num==1){
    41             int x,y,k;
    42             scanf("%d%d%d",&x,&y,&k);
    43             add(x,k);
    44             add(y+1,-k);
    45         }else{
    46             int r;
    47             scanf("%d",&r);
    48             printf("%d
    ",sum(r));
    49         }
    50     }
    51     return 0;
    52 }
    View Code

    qscoj16

    链接:http://qscoj.cn/problem/16/

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<string>
     5 using namespace std;
     6 const int maxn=100000+10;
     7 long long c[maxn];
     8 int n,m;
     9 int lowbit(int x){
    10     return x&(-x);
    11 }
    12 void add(int x,long long d){
    13     while(x<=n){
    14         c[x]+=d;
    15         x+=lowbit(x);
    16     }
    17 }
    18 long long sum(int x){
    19     long long ret=0;
    20     while(x>0){
    21         ret+=c[x];
    22         x-=lowbit(x);
    23     }
    24     return ret;
    25 }
    26 int main(int argc, char const *argv[])
    27 {
    28     /* code */
    29     scanf("%d%d",&n,&m);
    30     memset(c,0,sizeof(c));
    31     long long last=0;
    32     for(int i=1;i<=n;i++){
    33         long long x;
    34         scanf("%lld",&x);
    35         add(i,x-last);
    36         last=x;
    37     }
    38     while(m--){
    39         long long l,r,k;
    40         scanf("%lld%lld%lld",&l,&r,&k);
    41         add(l,k);
    42         add(r+1,-k);
    43     }
    44     for(int i=1;i<=n;i++)
    45     printf("%lld ",sum(i));
    46     printf("
    ");
    47     return 0;
    48 }
    View Code
  • 相关阅读:
    洛谷 P1401 城市(二分+网络流)
    洛谷 P2057 善意的投票(网络流最小割)
    洛谷 P1402 酒店之王
    二分图最大匹配的一些证明
    P2764 最小路径覆盖问题(网络流24题之一)
    洛谷 P2055 [ZJOI2009]假期的宿舍
    P2891 [USACO07OPEN]吃饭Dining(最大流+拆点)
    洛谷P1345 [USACO5.4]奶牛的电信(最小割)
    网络流24题之星际转移问题(洛谷P2754)
    LeetCode Unique Binary Search Trees
  • 原文地址:https://www.cnblogs.com/wolf940509/p/6489686.html
Copyright © 2020-2023  润新知