日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

线段树+树状数组

發布時間:2023/12/3 编程问答 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 线段树+树状数组 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

感覺這東西就是每棵線段樹管的區間變了,以前學的時候線段樹總是只管一個點或者管(1-i)這些點,但是這東西如果加上樹狀數組的思想,每棵線段樹管( i-(i&-i)+1 ~ i )這些區間,那么動態修改單點就不用nlog修改只用改這個點在那log棵線段樹改log*log次;查詢的話變慢了點,之前的 log變成了 log * log;
精品博客 講的真的很好 感謝大佬:
博客園 TaylorSwift13 的 樹狀數組套權值線段樹
動態逆序對
代碼

Dynamic Rankings
代碼

#include <iostream> #include <algorithm> #include <cstring> #include <sstream> using namespace std; typedef long long LL; const int N = 5e5 + 4; int n, m; int a[N], f[N]; int rt[N], ls[N<<6], rs[N<<6], val[N<<6], idx = 0;namespace seg {void modify(int &u, int l, int r, int x, int f){if(!u) u = ++idx;val[u] += f;if(l==r)return ;int mid = l+r>>1;x <= mid ? modify(ls[u], l, mid, x, f) : modify(rs[u], mid+1, r, x, f);}int quary(int u, int l, int r, int L, int R){if(!u||L>r||R<l)return 0;if(L<=l&&R>=r)return val[u];int mid = l+r>>1;return quary(ls[u], l, mid, L, R) + quary(rs[u], mid+1, r, L, R);} };namespace tree {int quary(int u, int l, int r){int sum = 0;for(int x = u;x >= 1;x -= (x&-x))sum += seg::quary(rt[x], 0, n+1, l, r);return sum;}void modify(int u,int g, int f){for(int x = u;x <= n;x += (x&-x))seg::modify(rt[x], 0, n+1, g, f);} };namespace tr{int tr[N]={};void modify(int u,int f){while(u<=n+1)tr[u]+=f,u+=(u&-u);}int quary(int u){int sum=0;while(u)sum+=tr[u],u-=(u&-u);return sum;} }int main() {scanf("%d%d",&n, &m);for(int i = 1;i <= n;i ++)scanf("%d",a + i);LL ans = 0;for(int i = 1;i <= n;i ++){ans += tree::quary(i-1, a[i]+1, n+1);tree::modify(i, a[i], 1);tr::modify(a[i], 1);f[a[i]] = i;}while(m --){int x;scanf("%d", &x); cout<<ans<<endl;ans -= tree::quary(f[x]-1, x+1, n+1);ans -= tr::quary(x-1) - tree::quary(f[x]-1, 0, x-1);tree::modify(f[x], x, -1);tr::modify(x, -1);}return 0; } #include <iostream> #include <algorithm> #include <cstring> #include <sstream> using namespace std;typedef long long ll; const int N = 1e5 + 4; int n, m; int rt[N], ls[N<<9], rs[N<<9], val[N<<9], idx; int x[N], cntx, y[N], cnty, a[N];int quary(int l, int r, int k) { if(l == r)return l;int sum = 0;for(int i = 0;i < cntx ;i ++)sum -= val[ls[x[i]]];for(int i = 0;i < cnty ;i ++)sum += val[ls[y[i]]];if(sum >= k){for(int i = 0;i < cntx ;i ++)x[i] = ls[x[i]];for(int i = 0;i < cnty ;i ++)y[i] = ls[y[i]];return quary(l, l+r>>1, k);}else {for(int i = 0;i < cntx ;i ++)x[i] = rs[x[i]];for(int i = 0;i < cnty ;i ++)y[i] = rs[y[i]];return quary((l+r>>1) + 1, r, k - sum);} }void modify(int &u, int l, int r, int x, int f) {if(!u)u = ++idx;val[u] += f;if(l == r)return ;int mid = l+r>>1;x <= mid ? modify(ls[u], l, mid, x, f) : modify(rs[u], mid+1, r, x, f); }int main() { scanf("%d%d", &n, &m);for(int i = 1;i <= n;i ++){scanf("%d", a+i);for(int u = i;u <= n;u +=(u&-u))modify(rt[u], 0, 1e9, a[i], 1);}while(m --){char c[2];int l, r, k;scanf("%s%d%d", c, &l, &r);if(c[0]=='Q'){scanf("%d", &k);cntx = cnty = 0;for(int j = l-1;j >= 1;j -= (j&-j)) x[cntx++] = rt[j];for(int u = r;u >= 1; u -= (u&-u)) y[cnty++] = rt[u];cout<<quary(0, 1e9, k)<<endl;}else{for(int u = l;u <= n;u +=(u&-u))modify(rt[u], 0, 1e9, a[l], -1);a[l] = r;for(int u = l;u <= n;u +=(u&-u))modify(rt[u], 0, 1e9, a[l], 1);}}return 0; }

總結

以上是生活随笔為你收集整理的线段树+树状数组的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。