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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

线段树、树状数组

發(fā)布時(shí)間:2023/12/10 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 线段树、树状数组 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
A 樹狀數(shù)組: 1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include <string.h> 5 using namespace std; 6 // 1h / 10min 7 const int maxn = 32001; 8 int c[maxn],ans[maxn]; // c[i] : 以i為橫坐標(biāo)的星星左側(cè)和下側(cè)星星的個(gè)數(shù), ans[i] : 某層的星星的個(gè)數(shù) 9 int x,y; 10 int lowbit(int x) 11 { 12 return x&(-x); 13 } 14 int sum(int x) // 計(jì)算橫坐標(biāo)為x的星星的level 15 { 16 int s = 0; 17 for (x ; x > 0 ; x -=lowbit(x)) 18 { 19 s += c[x]; 20 } 21 return s; 22 } 23 void insert(int x) 24 { 25 for (x ; x <= maxn ; x += lowbit(x)) 26 { 27 c[x]++; 28 } 29 } 30 int main() 31 { 32 int n; 33 while (scanf("%d",&n)!=EOF) 34 { 35 memset(c,0,sizeof(c)); 36 memset(ans,0,sizeof(ans)); 37 for (int i=0;i<n;i++) 38 { 39 scanf("%d%d",&x,&y); x++;// 橫坐標(biāo)整體往右移動一位 40 ans[sum(x)]++; 41 insert(x); 42 } 43 for (int i=0;i<n;i++) 44 cout << ans[i] << endl; 45 } 46 47 }

?

樹狀數(shù)組: https://www.cnblogs.com/hsd-/p/6139376.html https://blog.csdn.net/flushhip/article/details/79165701 https://blog.csdn.net/zheng0518/article/details/51119042 https://blog.csdn.net/kkkkahlua/article/details/76785265 https://blog.csdn.net/moep0/article/details/52770728 題目解析:https://blog.csdn.net/zhanghaoxian1/article/details/74275951
  • 有一點(diǎn)明白但還是不是很懂怎么轉(zhuǎn)換的過程,再重新順一遍過程。

線段樹

  • 自學(xué)困難的知識的時(shí)候,不要有畏難心理。所有的難知識都可以通過一定的方法,掰碎了一點(diǎn)一點(diǎn)消化吸收的,我只需要一個(gè)程序一個(gè)程序地編寫。在編寫的過程中,遇到不清楚的知識點(diǎn),一定要記下來!并且回去反復(fù)思考總結(jié)!我的問題總是反反復(fù)復(fù)的出現(xiàn),一如我踩過的坑,下次遇到這個(gè)坑的時(shí)候還是義無反顧地跳進(jìn)去,這就是我最大的問題!不總結(jié)!犯重復(fù)的錯(cuò)誤!而且你要有時(shí)刻準(zhǔn)備好的狀態(tài),不要畏畏縮縮的,大家都是這么過來的,慢慢來,還有兩個(gè)月的時(shí)間,每天做五道題,你會超越絕大多數(shù)的人。
  • 創(chuàng)建線段樹和中序遍歷線段樹的代碼寫不對,爆出segment fault這等高級段錯(cuò)誤,與結(jié)構(gòu)體、指針、構(gòu)造函數(shù)有關(guān)。
  • 菜鳥都能理解的線段樹
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 using namespace std; 5 6 struct line 7 { 8 int l,r,count; 9 struct line *lchild,*rchild; 10 line(int a,int b) 11 { 12 l = a;r = b;count = 0; 13 lchild = NULL; 14 rchild = NULL; 15 } 16 }; 17 18 19 const int maxn = 20; 20 int a[maxn][2],p[maxn]; 21 22 /* 23 24 指針一定要初始化了在使用!!! 25 兩種初始化創(chuàng)建的方法: 第一種一直調(diào)試不過原因: 26 1. line中指針一定要初始化為NULL 27 2. 傳參數(shù)的時(shí)候要傳引用。指針的引用。不然僅僅是復(fù)制一個(gè)指針并不是在原來的指針上改變。 28 如果改變影響到它自身的話就用引用。 29 */ 30 // 這個(gè)創(chuàng)建樹也不太會寫誒 31 void createLine(line* &root,int left,int right) 32 { 33 root = new line(left,right); 34 if (left < right) // l==r 葉節(jié)點(diǎn)時(shí)便不往下繼續(xù)分了 35 { 36 int mid = (left+right)/2; 37 createLine(root->lchild,left,mid); 38 createLine(root->rchild,mid+1,right); 39 } 40 } 41 42 /* 43 void createLine(line *root) { 44 int left = root->l; 45 int right = root->r; 46 if (left < right) { 47 int mid = (left + right) / 2; 48 line *lc = new line(left, mid); 49 line *rc = new line(mid + 1, right); 50 root->lchild = lc; 51 root->rchild = rc; 52 createLine(lc); 53 createLine(rc); 54 } 55 } 56 */ 57 void inOrder(line *root) 58 { 59 60 if ( root !=NULL) 61 { 62 inOrder(root->lchild); 63 cout << "["<<root->l<<","<<root->r<<"]" << root->count<< endl; 64 inOrder(root->rchild); 65 } 66 } 67 void insertLine(line* &root,int l, int r ) 68 { 69 // 把[l,r]插入到線段樹中 70 cout << root->l << "," << root->r << endl; 71 if (root->l == l && root->r == r) 72 { 73 // 1. 剛好重合 74 root->count ++; 75 return ; 76 } 77 else 78 { 79 int mid = (root->l+root->r)/2; // 判斷線段在root的左半?yún)^(qū)間還是右半?yún)^(qū)間 80 if (r <= mid) // 左半?yún)^(qū)間 81 { 82 insertLine(root->lchild,l,r); 83 } 84 else if ( l > mid ) // 右半?yún)^(qū)間 85 { 86 insertLine(root->rchild,l,r); 87 } 88 else 89 { 90 // 從中間分開 91 int mid_l = (l+r)/2; // 把小線段從中間分開而不是用root的區(qū)間 ? 用root的區(qū)間可以嗎? 92 insertLine(root->lchild,l,mid_l); 93 insertLine(root->rchild,mid_l+1,r); 94 } 95 } 96 97 } 98 // 這個(gè)遞歸不太會寫誒 99 int getCount(line *root,int x) 100 { // 每一層的ans = 根的count + 左子樹count + 右子樹count 101 int ans = 0; // count 個(gè)數(shù) 102 int mid = (root->l+root->r)/2; 103 if (root->l <= x && root->r >= x) // 在區(qū)間范圍內(nèi) 104 ans += root->count; 105 if (root->l == root->r) 106 { 107 return ans; 108 } 109 if (x > mid) 110 { 111 ans += getCount(root->rchild,x); 112 } 113 else 114 { 115 ans +=getCount(root->lchild,x); 116 } 117 return ans; 118 } 119 int main() 120 { 121 int n,m; 122 // 給定N條線段 , M個(gè)點(diǎn), 判斷每個(gè)點(diǎn)在幾個(gè)線段中出現(xiàn)過 123 while (cin >> n >> m) 124 { 125 // 輸入線段和點(diǎn) 126 int l = 65515,r = -65515; 127 for (int i=0;i<n;i++) 128 { 129 cin >>a[i][0] >> a[i][1]; 130 if (a[i][0] < l) 131 { 132 l = a[i][0]; 133 } 134 if (a[i][1] > r) 135 { 136 r = a[i][1]; 137 } 138 } 139 for (int i=0;i<m;i++) cin >> p[i]; 140 // 創(chuàng)建線段樹 141 // 1. 找到給定線段所覆蓋的最大區(qū)間范圍,創(chuàng)建以該范圍為根節(jié)點(diǎn)的線段樹 142 line *root = new line(l,r); 143 createLine(root,l,r); 144 // createLine(root); 145 // inOrder(root); 146 for (int i = 0;i<n;i++) 147 { 148 insertLine(root,a[i][0],a[i][1]); // 依次把各條線段插入線段樹 149 } 150 for (int i=0;i<m;i++) 151 { 152 // 對于每一個(gè)點(diǎn) 153 cout << getCount(root,i)<< endl; 154 } 155 } 156 }

?

敵兵布陣

詳細(xì)的線段樹入門+題目講解(提交時(shí)超時(shí)了) 不超時(shí)答案 1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include <string> 5 #include <string.h> 6 using namespace std; 7 // 1h 35 8 // (step<<1)+1 括號必須加,優(yōu)先級問題 9 const int maxn = 1000000; // 數(shù)組長度定義為多少?? 10 struct node 11 { 12 int left,right,value; 13 }tree[maxn]; 14 /* 15 void build(int l,int r,int step) 16 { 17 // 1. 第step個(gè)結(jié)點(diǎn)的賦值 18 tree[step].left = l; 19 tree[step].right = r; 20 tree[step].value = 0; 21 // cout << "結(jié)點(diǎn):"<< step << ",左:" << l << ",右:" << r<< endl; 22 // 2. 遞歸邊界 23 if (l == r) 24 return ; 25 // 3. 一分為2,繼續(xù)遞歸創(chuàng)建子樹 26 int mid = (l+r)>>1; // 右移1位 = 除以2, 為什么不直接除以2 ?? 27 build(l,mid,step<<1); // step * 2 左子樹 28 build(mid+1,r,(step<<1)+1); // step * 2 + 1右子樹 29 } 30 */ 31 void init(int n)//新建一個(gè)線段樹 32 { 33 int i,k; 34 for(k = 1; k<n; k<<=1); 35 for(i = k; i<2*k; i++) 36 { 37 tree[i].left = tree[i].right = i-k+1; 38 tree[i].value = 0; 39 } 40 for(i = k-1; i>0; i--) 41 { 42 tree[i].left = tree[2*i].left; 43 tree[i].right = tree[2*i+1].right; 44 tree[i].value = 0; 45 } 46 } 47 void update(int l,int r,int value,int step) 48 { 49 tree[step].value += value; 50 // cout <<"結(jié)點(diǎn):"<< step << "加上" << value <<endl; 51 // 遞歸邊界 52 if (tree[step].left == tree[step].right ) // 更新到葉子結(jié)點(diǎn) , 為什么不能寫成left = l && right = r ?? 53 { 54 // tree[step].value = value; 55 // cout << "step:"<< step << ",l:" << l << ",r:" << r<< value <<endl; 56 return; 57 } 58 int mid = (tree[step].left + tree[step].right) >> 1; 59 if (r <= mid) 60 { 61 // 線段在根節(jié)點(diǎn)的左半?yún)^(qū)間 62 update(l,r,value,step<<1); 63 }else if (l > mid) // 右半?yún)^(qū)間 64 { 65 update(l,r,value,(step<<1)+1); 66 }else 67 { 68 // l,r 跨越了mid,分別更新 69 update(l,mid,value,step<<1); 70 update(mid+1,r,value,(step<<1)+1); 71 } 72 } 73 int query(int l,int r,int step) // 求 l - r的和 ???? 74 { 75 // if (tree[step].left == tree[step].right) 76 if(l == tree[step].left && r == tree[step].right) 77 { 78 // printf("返節(jié)點(diǎn)%d的值%d\n",step,tree[step].value); 79 return tree[step].value; 80 } 81 int mid = (tree[step].left + tree[step].right) >> 1; 82 if(r <= mid) 83 { 84 // printf("結(jié)點(diǎn):%d 查詢%d到%d \n",step,l,r); 85 return query(l, r, step<<1); 86 } 87 if(l > mid) 88 { 89 // printf("結(jié)點(diǎn):%d 查詢%d到%d \n",step,l,r); 90 return query(l, r, (step<<1)+1); 91 } 92 else 93 { 94 // printf("結(jié)點(diǎn):%d 查詢%d到%d 和%d %d \n",step,l,mid,mid+1,r); 95 return query(l, mid, step<<1) + query(mid+1, r, (step<<1)+1); 96 } 97 } 98 int main() 99 { 100 int t,n,ai,a,b; 101 char order[10]; 102 scanf("%d",&t); 103 for (int j = 1;j<=t;j++) 104 { 105 scanf("%d",&n); 106 // build(1,n,1); 107 init(n); 108 // 依次更新每個(gè)營地的人數(shù)值 109 for (int i=1;i<=n;i++) 110 { 111 scanf("%d",&ai); 112 update(i,i,ai,1); 113 } 114 printf("Case %d:\n",j); 115 while (scanf("%s",order)!=EOF && strcmp(order,"End")!=0) 116 { 117 cin >> a >> b; 118 if (strcmp(order,"Add") == 0) 119 { 120 update(a,a,b,1); 121 } 122 if (strcmp(order,"Sub") == 0) 123 { 124 update(a,a,-b,1); 125 } 126 if (strcmp(order,"Query")==0) 127 { 128 cout << query(a,b,1) << endl; 129 } 130 } 131 } 132 }

?

  • 我他喵的研究了三個(gè)小時(shí)之后終于accept而且我好像看懂其中的原理了我很開心。Hhhhhh這大概就是計(jì)算機(jī)的女人絕不認(rèn)輸?shù)木癜?#xff01;

C I hate it

  • 改了改update和query
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include <string> 5 #include <string.h> 6 using namespace std; 7 const int maxn = 1000000; 8 struct node 9 { 10 int left,right,value; 11 }tree[maxn]; 12 13 void build(int n) 14 { 15 int i,k; 16 for (k=1; k < n ; k = k<<1); // k是超過n的最小2的倍數(shù) 17 for (i = k;i < 2*k ; i++) // 完全二叉樹 18 { 19 tree[i].left = tree[i].right = i - k + 1; 20 tree[i].value = 0; 21 // cout << "node : " << i << ",left:" << i - k + 1 << ",right :" << i-k+1 << endl; 22 } 23 for ( i = k-1 ;i>0;i--) 24 { 25 tree[i].left = tree[2*i].left; 26 tree[i].right = tree[2*i+1].right; 27 tree[i].value = 0; 28 // cout << "node : " << i << ",left:" << tree[2*i].left << ",right :" << tree[2*i+1].right << endl; 29 } 30 } 31 void update(int l,int r,int value,int step) 32 { // tree[step]存儲左子樹和右子樹中較大的數(shù) 33 if (tree[step].left == tree[step].right) 34 { // 葉子結(jié)點(diǎn)時(shí)賦值value 35 tree[step].value = value; 36 return ; 37 } 38 int mid = (tree[step].left + tree[step].right) >> 1; 39 if (r <= mid) 40 update(l,r,value,step<<1); 41 else if (l>mid) 42 update(l,r,value,(step<<1)+1); 43 else 44 { 45 update(l,mid,value,step<<1); 46 update(mid+1,r,value,(step<<1)+1); 47 } 48 tree[step].value = max(tree[step<<1].value,tree[(step<<1)+1].value); 49 // cout << "node : " << step << ",left:" << tree[step<<1].value << ",right :" << tree[(step<<1)+1].value << endl; 50 } 51 int query(int l,int r,int step) 52 { 53 // 查詢l - r 中的最大值 54 55 if (tree[step].left == l && tree[step].right == r) 56 return tree[step].value; 57 58 int mid = (tree[step].left + tree[step].right) >> 1; 59 if (r <= mid) 60 return query(l,r,step<<1); 61 else if (l>mid) 62 return query(l,r,(step<<1)+1); 63 else 64 { 65 return max(query(l,mid,step<<1),query(mid+1,r,(step<<1)+1)); 66 } 67 68 } 69 int main() 70 { 71 int n,m,grade,a,b; 72 char cmd[3]; 73 while (scanf("%d%d",&n,&m)!=EOF) 74 { 75 // 1. 創(chuàng)建線索樹 76 build(n); 77 // 2. 輸入數(shù)據(jù)并更新線索樹 78 for (int i=1;i<=n;i++) 79 { 80 scanf("%d",&grade); 81 update(i,i,grade,1); 82 } 83 // cout << tree[1].value << endl; 84 // 3. m條操作依次執(zhí)行 85 for (int i=0;i<m;i++) 86 { 87 88 scanf("%s%d%d",cmd,&a,&b); 89 if (cmd[0] == 'Q') 90 { 91 cout << query(a,b,1) << endl; // 查詢a-b中的最大值 92 } 93 if (cmd[0] == 'U') 94 { 95 update(a,a,b,1); 96 } 97 98 } 99 } 100 }

?

但是看到有在build部分修改函數(shù)的: 線段樹 最大最小模板

D just a hook

1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include <string> 5 #include <string.h> 6 using namespace std; 7 8 const int maxn = 1000000; 9 struct node 10 { 11 int left,right,value; 12 }tree[maxn]; 13 14 void build(int n) 15 { 16 int i,k; 17 for (k=1;k<n;k=k<<1); 18 for (i=k;i<k*2;i++) 19 { 20 tree[i].left = tree[i].right = i-k+1;tree[i].value = 0; 21 // printf("結(jié)點(diǎn):%d,左邊:%d,右邊:%d\n",i,i-k+1,i-k+1); 22 } 23 for (i=k-1;i>0;i--) 24 { 25 tree[i].left = tree[2*i].left; 26 tree[i].right = tree[2*i+1].right; 27 tree[i].value = 0; 28 // printf("結(jié)點(diǎn):%d,左邊:%d,右邊:%d\n",i,tree[i<<1].left,tree[(i<<1)+1].right); 29 } 30 } 31 32 void update(int l,int r,int value ,int step) 33 { 34 tree[step].value += value; 35 // printf("結(jié)點(diǎn):%d,左邊:%d,右邊:%d,value:%d\n",step,tree[step].left,tree[step].right,tree[step].value); 36 if (tree[step].left == tree[step].right) 37 { 38 return ; 39 } 40 int mid = (tree[step].left+tree[step].right)>>1; 41 if (r <= mid) 42 update(l,r,value,step<<1); 43 else if (l>mid) 44 update(l,r,value,(step<<1)+1); 45 else 46 { 47 update(l,mid,value,step<<1); 48 update(mid+1,r,value,(step<<1)+1); 49 } 50 } 51 int main() 52 { 53 int t,n,q,a,b,c,x; 54 scanf("%d",&t); 55 for (int i = 1;i<=t;i++) 56 { 57 scanf("%d%d",&n,&q); // stick number & oper number 58 build(n); 59 for (int g=1;g<=n;g++) 60 update(g,g,1,1); 61 62 for (x=1;x<n;x=x<<1); 63 for (int j=1;j<=q;j++) 64 { 65 scanf("%d%d%d",&a,&b,&c); // a-b 修改mental kind 66 for (int k = a;k<=b;k++) 67 update(k,k,c-tree[x+k-1].value,1); 68 } 69 printf("Case %d:The total value of the hook is %d\n",i,tree[1].value); 70 71 72 } 73 74 }

?

  • 區(qū)間更新 = 循環(huán)+每個(gè)點(diǎn)的單點(diǎn)更新 = Time limited exceed

轉(zhuǎn)載于:https://www.cnblogs.com/twomeng/p/9509823.html

總結(jié)

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

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。