lowbit运算 二进制数右端第一位1的位权
lowbit(x) = x&(-x)
定义、查询、修改
树状数组是一种支持 单点修改 和 区间查询 的,代码量小的数据结构。 初步感受————oi_wiki 管辖区间 我们记 x 二进制最低位 1 以及后面的 0 组成的数为 lowbit(x),那么 c[x] 管辖的区间就是 [x-lowbit(x)+1, x]
树状数组1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 #include <bits/stdc++.h> using namespace std;typedef long long ll;const ll N = 5e5 +10 ;ll a[N]; ll c[N]; int n,q;ll query (int x) { ll sum=0 ; for (;x;x-=x&(-x)) { sum+=c[x]; } return sum; } void modify (int x,ll s) { for (;x<=n;x+=x&(-x)) { c[x]+=s; } } int main () { scanf ("%d%d" ,&n,&q); for (int i=1 ;i<=n;i++) { scanf ("%lld" ,&a[i]); modify (i,a[i]); } for (int i=0 ;i<q;i++) { int ty; scanf ("%d" ,&ty); if (ty==1 ) { int x,d; scanf ("%d%d" ,&x,&d); modify (x,d); } else { int x,y; scanf ("%d%d" ,&x,&y); printf ("%lld\n" ,query (y)-query (x-1 )); } } return 0 ; }
树状数组2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 #include <bits/stdc++.h> using namespace std;typedef long long ll;typedef unsigned long long u64; const int N = 5e5 +10 ;int n,q;template <class T > struct BIT { T c[N]; int size; void resize (int sum) {size=sum;} T query (int x) { assert (x<=size); T sum=0 ; for (;x;x-=x&(-x)) { sum+=c[x]; } return sum; } void modify (int x,T s) { assert (x!=0 ); for (;x<=n;x+=x&(-x)) { c[x]+=s; } } }; BIT <u64> c1,c2; int main () { scanf ("%d%d" ,&n,&q); c1.resize (n); c2.resize (n); for (int i=1 ;i<=n;i++) { int a; scanf ("%llu" ,&a); c1.modify (i,a); c1.modify (i+1 ,-a); c2.modify (i,i*a); c2.modify (i+1 ,(i+1 )*(-a)); } for (int i=0 ;i<q;i++) { int ty; scanf ("%d" ,&ty); if (ty==1 ) { int l,r; u64 d; scanf ("%d%d%llu" ,&l,&r,&d); c1.modify (l,d); c1.modify (r+1 ,-d); c2.modify (l,l*d); c2.modify (r+1 ,(r+1 )*(-d)); } else { int x; scanf ("%llu" ,&x); u64 ans=c1.query (x); printf ("%llu\n" ,ans); } } return 0 ; }
区间修改+查询前缀
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 #include <bits/stdc++.h> using namespace std;typedef long long ll;typedef unsigned long long u64; const int N = 201000 ;int n,q;template <class T > struct BIT { T c[N]; int size; void resize (int sum) {size=sum;} T query (int x) { assert (x<=size); T sum=0 ; for (;x;x-=x&(-x)) { sum+=c[x]; } return sum; } void modify (int x,T s) { assert (x!=0 ); for (;x<=n;x+=x&(-x)) { c[x]+=s; } } }; BIT <u64> c1,c2; int main () { scanf ("%d%d" ,&n,&q); c1.resize (n); c2.resize (n); for (int i=0 ;i<q;i++) { int ty; scanf ("%d" ,&ty); if (ty==1 ) { int l,r; u64 d; scanf ("%d%d%llu" ,&l,&r,&d); c1.modify (l,d); c1.modify (r+1 ,-d); c2.modify (l,l*d); c2.modify (r+1 ,(r+1 )*(-d)); } else { int x; scanf ("%llu" ,&x); u64 ans=(x+1 )*c1.query (x)-c2.query (x); printf ("%llu\n" ,ans); } } return 0 ; }
区间查询 1 2 3 4 5 6 7 8 9 10 11 12 13 ll query (int x) { ll sum=0 ; for (;x;x-=x&(-x)) { sum+=c[x]; } return sum; } query (y)-query (x-1 );
单点修改 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 void modify (int x,ll s) { for (;x<=n;x+=x&(-x)) { c[x]+=s; } } modify (x,d); a[x]+=d; modify (x,d-a[x]); a[x]=d;
xxxxxxxxxx C++ 差分
单点查询 前缀和之差:query(x)-query(x-1); 差分应用: c1.query(x) / c[x]=d1+d2+..+dx
逆序对 i<j && a[i]>a[j]
树状数组解法 1 扫描线:静态——>动态 2 对权值开树状数组(后缀和查询——>前缀和查询)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 #include <bits/stdc++.h> using namespace std;typedef long long ll;const ll N = 5e5 +10 ;int tree[N],ranks[N],n;ll ans; struct point { int num,val; }a[N]; inline bool cmp (point x,point y) { if (x.val==y.val) return x.num<y.num; return x.val<y.val; } ll query (int x) { ll sum=0 ; for (;x;x-=x&(-x)) { sum+=tree[x]; } return sum; } void modify (int x,ll s) { for (;x<=n;x+=x&(-x)) { tree[x]+=s; } } int main () { scanf ("%d" ,&n); for (int i=1 ;i<=n;i++) { scanf ("%lld" ,&a[i].val); a[i].num=i; } sort (a+1 ,a+n+1 ,cmp); for (int i=1 ;i<=n;i++) { ranks[a[i].num]=i; } for (int i=1 ;i<=n;i++) { modify (ranks[i],1 ); ans+=i-query (ranks[i]); } printf ("%lld\n" ,ans); return 0 ; }
归并解法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 #include <bits/stdc++.h> using namespace std;typedef long long ll;const int N =1e5 +10 ;void solve () { int n; cin>>n; vector<ll> a (n+1 ) ; for (int i=1 ;i<=n;i++) { cin>>a[i]; } ll ans=0 ; auto dfs=[&](auto dfs,int s,int t)->void { if (s>=t) return ; int mid=s+t>>1 ; dfs (dfs,s,mid),dfs (dfs,mid+1 ,t); vector<ll> f (a.begin()+s,a.begin()+mid+1 ) , g (a.begin()+mid+1 ,a.begin()+t+1 ) ; for (ll i=0 ,j=0 ,p=s;i<f.size () || j<g.size ();) { if (i>=f.size ()) a[p++]=g[j++]; else if (j>=g.size ()) a[p++]=f[i++]; else if (f[i]<=g[j]) a[p++]=f[i++]; else a[p++]=g[j++],ans+=f.size ()-i; } }; dfs (dfs,1 ,n); cout<<ans<<endl; return ; } int main () { ios::sync_with_stdio (0 ); cin.tie (0 ); cout.tie (0 ); int t=1 ; while (t--) { solve (); } return 0 ; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 #include <bits/stdc++.h> using namespace std;typedef long long ll;typedef double db;const int N = 1e5 + 10 ;const ll mod = 1e9 + 7 ;int a[N], b[N], c[N];ll sum1, sum2; void mergesort (int l, int r, int a[], ll& ans) { if (l >= r) return ; int mid = (l + r) / 2 , i = l, j = mid + 1 , k = l; mergesort (l, mid, a, ans), mergesort (mid + 1 , r, a, ans); while (i <= mid && j <= r) if (a[i] > a[j]) c[k++] = a[j++], ans += mid - i + 1 ; else c[k++] = a[i++]; while (i <= mid) c[k++] = a[i++]; while (j <= r) c[k++] = a[j++]; for (int i = l; i <= r; i++) a[i] = c[i]; return ; } void deer () { int n; cin >> n; for (int i = 0 ; i < n; ++i) cin >> a[i]; for (int i = 0 ; i < n; ++i) cin >> b[i]; sum1 = sum2 = 0 ; mergesort (0 , n - 1 , a, sum1), mergesort (0 , n - 1 , b, sum2); bool flag = 0 ; for (int i = 0 ; i < n; ++i) if (a[i] != b[i]) { flag = 1 ; break ; } if (flag == 1 ) cout << "NO\n" ; else if ((sum1^sum2) & 1 ) cout << "NO\n" ; else cout << "YES\n" ; } int main () { ios::sync_with_stdio (0 ); cin.tie (0 ); cout.tie (0 ); int t = 1 ; cin >> t; while (t--) { deer (); } return 0 ; }
树状数组上二分 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 #include <bits/stdc++.h> using namespace std;typedef long long ll;const ll N = 5e5 +10 ;ll a[N]; ll c[N]; int n,q;int query (ll x) { ll t=0 ; int pos=0 ; for (int j=18 ;j>=0 ;j--) { if (pos+(1 <<j)<=n && t+c[pos+(1 <<j)]<=x) { pos+=(1 <<j); t+=c[pos]; } } return pos; } void modify (int x,ll s) { for (;x<=n;x+=x&(-x)) { c[x]+=s; } } int main () { scanf ("%d%d" ,&n,&q); for (int i=1 ;i<=n;i++) { scanf ("%lld" ,&a[i]); modify (i,a[i]); } for (int i=0 ;i<q;i++) { int ty; scanf ("%d" ,&ty); if (ty==1 ) { int x,d; scanf ("%d%d" ,&x,&d); modify (x,d-a[x]); a[x]=d; } else { ll s; scanf ("%lld" ,&s); printf ("%lld\n" ,query (s)); } } return 0 ; }
高维树状数组 二维树状数组 n*m个数:a[1,1],a[1,2],a[1,3],…,a[1,m],…,a[n,m] q个操作:
1 x y d 修改a[x,y]=d;
2 x y 查询 i=(1x),j=(1y)的a[i,j]之和
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 #include <bits/stdc++.h> using namespace std;typedef long long ll;const ll N = 510 ;int n,m,q;ll a[N][N]; ll c[N][N]; ll query (int x,int y) { ll sum=0 ; for (int p=x;p;p-=p&(-p)) { for (int q=y;q;q-=q&(-q)) { sum+=c[p][q]; } } return sum; } void modify (int x,int y,ll s) { for (int p=x;p<=n;p+=p&(-p)) { for (int q=y;q<=m;q+=q&(-q)) { c[p][q]+=s; } } } int main () { scanf ("%d%d%d" ,&n,&m,&q); for (int i=1 ;i<=n;i++) { for (int j=1 ;j<=m;j++) { scanf ("%d" ,&a[i][j]); modify (i,j,a[i][j]); } } for (int i=0 ;i<q;i++) { int ty; scanf ("%d" ,&ty); if (ty==1 ) { int x,y,d; scanf ("%d%d%d" ,&x,&y,&d); modify (x,y,d-a[x][y]); a[x][y]=d; } else { int x,y; scanf ("%d%d" ,&x,&y); printf ("%lld\n" ,query (x,y)); } } return 0 ; }