关于G - Naive Operations的一些试探性想法
https://vjudge.net/contest/310809#problem/G
只是一些瞎想
没学过线段树,不会区间更新,不会做维护(我就是一条咸鱼
花了五分钟在网上看了一下线段树的思想,大概明白了怎么个用法,但是没有背模板也不会写
所以考虑用树状数组
用二维数组叠成线段树的样子
简单讲下想法:
核心:二维数组写线段树
第1层是目标数列;
第2层存储每相邻2项之和,第3层存储每相邻4项之和,以此类推...
第n层存储每相邻2^n项之和;
(题目要求1≤n,q≤100000不超过2^17,17*100000的矩阵可以完成)
一个简单的例子 16 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 add 1 12 12 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 12 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 12 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 4 0 0 0 4 0 0 0 4 0 0 0 0 0 0 0 2 0 2 0 2 0 2 0 2 0 2 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0
每次 add 操作,对a数组对应元素+1,
满足a[i]==b[i]则置零, 找到tree数组底层对应元素,从该结点到根节点的路径都标记上+1;
访问路径结点通过数组下标的计算实现。
query操作麻烦一些,
一方面要判断能取到的最大段,另一方面要定位端点,把剩下的部分继续拆分。
通过一个l,r分别除一个整数div = 2^n,找到当前端点所在的区段,
div从上限开始,每次减半,
若可以取到当前大小的整段,把当前整段的权值加到res,并记录下断电,
对裁剪后两边的段进行相同操作,
因为区段(l,r)是连续的,每次断开断点为2^n,所以当前状态最多有两个不相接段;
另外当l,r为2^n点时可以有简化计算。
很遗憾的是这段代码仅通过了样例和部分测试组,所以并没有算过题
并且这种实现方法非常蹩脚 debug基本靠笔算
所以以后肯定老老实实背模板,也不会这么瞎鸡乱搞了
绿皮车代码仅供娱乐
1 #include <iostream> 2 using namespace std; 3 typedef long long ll; 4 5 int sum[17][100006] = {0}; 6 int a[100006] = {0}; 7 int b[100006] = {0}; 8 char tell[6] = {0}; 9 10 int main(){ 11 int n , q ; 12 int l , r ; 13 cin >> n >> q; 14 for (int i = 0;i<n;i++){ 15 cin >> b[i]; 16 }//建树,完成输入 17 while(q--){ 18 cin >> tell >> l >> r; 19 if(tell[0]=='a'){//add操作 20 for(int i = l-1;i<r;i++){ 21 a[i]++;//对a累加 22 if (a[i]>=b[i]){//a累加到b时 23 for(int j = 0,k = 1;j<17;j++){
//该节点到根节点路径上标记+1 24 sum[16-j][i/k*k]++; 25 k*=2; 26 } 27 a[i] = 0;//a置零 28 } 29 } 30 } 31 else if(tell[0]=='q'){//query操作 32 bool s1 = 0;//端点是否截断在2^n位置 33 int res = 0;//结果 34 int l1 = -1 , r1 = -1;//拆分后用的新断点 35 for(int i = 0,div= 65536;i<17;i++){
//div从2^16开始,每次减半 36 if(l1==-1 && r1==-1){
//判断是否被截取过 37 if(l/div==0 && l/div+1 < r/div){
//能截出当前最大段时 38 l1 = l/div+1; 39 r1 = r/div; 40 for(int j = l1; j<r1 ; j++){ 41 res+=sum[i][j*div]; 42 } 43 } 44 else if(l/div!=0 && l/div < r/div) { 45 l1 = l/div; 46 r1 = r/div; 47 for(int j = l1; j<r1 ; j++){ 48 res+=sum[i][j*div]; 49 } 50 } 51 else if( (l-1)%div==0){ 52 l1 = l/div; 53 r1 = r/div; 54 for(int j = l1; j<r1 ; j++){ 55 res+=sum[i][j*div]; 56 } 57 s1 = 1; 58 }//求和,移动断点,完成截取 59 } 60 else{//已经截成了两段时 61 l1 *=2 ; r1*=2; 62 if(l/div==0 && l/div+1 < l1){ 63 for(int j = l/div+1 ; j<l1 ; j++){ 64 res+=sum[i][j*div]; 65 } 66 l1 = l/div+1; 67 } 68 else if(l/div!=0 && l/div < r/div) { 69 for(int j = l/div ; j<l1 ; j++){ 70 res+=sum[i][j*div]; 71 } 72 l1 = l/div; 73 } 74 else if( (l-1)%div==0){ 75 if(s1 == 1); 76 else{ 77 for(int j = l/div; j<l1 ; j++){ 78 res+=sum[i][j*div]; 79 } 80 s1 = 1; 81 } 82 }//完成左边段截取 83 if(r1 < r/div){ 84 for(int j = r1 ; j<r/div ; j++){ 85 res+=sum[i][j*div]; 86 } 87 r1 = r/div; 88 } 89 }//完成右边段截取 90 div >>= 1;//div减半 91 } 92 cout<<res<<endl; 93 } 94 } 95 }
带debug输出的版本,供自己以后心情好了翻出来改
1 #include <iostream> 2 #include <iomanip> 3 using namespace std; 4 5 typedef long long ll; 6 7 int sum[17][100006] = {0}; 8 int a[100006] = {0}; 9 int b[100006] = {0}; 10 char tell[6] = {0}; 11 12 int main() 13 { 14 int n , q ; 15 int l , r ; 16 cin >> n >> q; 17 for (int i = 0;i<n;i++) 18 { 19 cin >> b[i]; 20 } 21 while(q--) 22 { 23 cin >> tell >> l >> r; 24 if(tell[0]=='a') 25 { 26 for(int i = l-1;i<r;i++) 27 { 28 a[i]++; 29 if (a[i]>=b[i]) 30 { 31 for(int j = 0,k = 1;j<17;j++) 32 { 33 sum[16-j][i/k*k]++; 34 k*=2; 35 } 36 a[i] = 0; 37 } 38 39 } 40 for(int j = 0;j<17;j++) // 41 { 42 for(int k = 0;k<16;k++) 43 cout<<setw(2)<<sum[j][k]<<" "; 44 cout<<endl; 45 } 46 47 } 48 else if(tell[0]=='q') 49 { 50 bool s1 = 0; 51 int res = 0; 52 int l1 = -1 , r1 = -1; 53 for(int i = 0,div= 65536;i<17;i++) 54 { 55 if(l1==-1 && r1==-1) 56 { 57 if(l/div==0 && l/div+1 < r/div) 58 { 59 l1 = l/div+1; 60 r1 = r/div; 61 for(int j = l1; j<r1 ; j++) 62 { 63 res+=sum[i][j*div]; 64 } 65 //cout<<"!!"<<res<<' '<<div<<" "<<i<<" "<<l1<<" "<<r1<<" A1"<<endl;// 66 } 67 else if(l/div!=0 && l/div < r/div) 68 { 69 l1 = l/div; 70 r1 = r/div; 71 for(int j = l1; j<r1 ; j++) 72 { 73 res+=sum[i][j*div]; 74 } 75 //cout<<"!!"<<res<<' '<<div<<" "<<i<<" "<<l1<<" "<<r1<<" A2"<<endl;// 76 } 77 else if( (l-1)%div==0) 78 { 79 l1 = l/div; 80 r1 = r/div; 81 for(int j = l1; j<r1 ; j++) 82 { 83 res+=sum[i][j*div]; 84 } 85 s1 = 1; 86 //cout<<"!!"<<res<<' '<<div<<" "<<i<<" "<<l1<<" "<<r1<<" B"<<endl;// 87 } 88 } 89 else 90 { 91 l1 *=2 ; r1*=2; 92 if(l/div==0 && l/div+1 < l1) 93 { 94 for(int j = l/div+1 ; j<l1 ; j++) 95 { 96 res+=sum[i][j*div]; 97 } 98 l1 = l/div+1; 99 //cout<<"!!"<<res<<' '<<div<<" "<<i<<" "<<l1<<" "<<r1<<" L11"<<endl;// 100 } 101 else if(l/div!=0 && l/div < r/div) 102 { 103 for(int j = l/div ; j<l1 ; j++) 104 { 105 res+=sum[i][j*div]; 106 } 107 l1 = l/div; 108 //cout<<"!!"<<res<<' '<<div<<" "<<i<<" "<<l1<<" "<<r1<<" L12"<<endl;// 109 } 110 else if( (l-1)%div==0) 111 { 112 if(s1 == 1); 113 else 114 { 115 for(int j = l/div; j<l1 ; j++) 116 { 117 res+=sum[i][j*div]; 118 } 119 s1 = 1; 120 //cout<<"!!"<<res<<' '<<div<<" "<<i<<" "<<l1<<" "<<r1<<" L2"<<endl;// 121 } 122 123 } 124 125 if(r1 < r/div) 126 { 127 for(int j = r1 ; j<r/div ; j++) 128 { 129 res+=sum[i][j*div]; 130 } 131 r1 = r/div; 132 //cout<<"!!"<<res<<' '<<div<<" "<<i<<" "<<l1<<" "<<r1<<" R"<<endl;// 133 } 134 } 135 div >>= 1; 136 } 137 cout<<res<<endl; 138 } 139 } 140 }