随便补了几道题,可能也就能写出来这几道吧。最近被搜索虐爆了,要抓紧去看搜索,随便写写就溜,备忘一下线段树新的板子(以前的不好用,太垃圾了)
A.逆序数
时间限制:C/C++ 2秒,其他语言4秒
空间限制:C/C++ 131072K,其他语言262144K
64bit IO Format: %lld
空间限制:C/C++ 131072K,其他语言262144K
64bit IO Format: %lld
题目描述
在一个排列中,如果一对数的前后位置与大小顺序相反,即前面的数大于后面的数,那么它们就称为一个逆序。一个排列中逆序的总数就称为这个排列的逆序数。比如一个序列为4 5 1 3 2, 那么这个序列的逆序数为7,逆序对分别为(4, 1), (4, 3), (4, 2), (5, 1), (5, 3), (5, 2),(3, 2)。
输入描述:
第一行有一个整数n(1 <= n <= 100000), 然后第二行跟着n个整数,对于第i个数a[i],(0 <= a[i] <= 100000)。
输出描述:
输出这个序列中的逆序数
示例1
输入
5 4 5 1 3 2
输出
7
这道题目就是找每个数的贡献就可以。
代码:
1 //A 2 #include<iostream> 3 #include<cstring> 4 #include<cstdio> 5 #include<cmath> 6 #include<algorithm> 7 #include<queue> 8 #include<map> 9 using namespace std; 10 typedef long long ll; 11 const int maxn=1e5+10; 12 int a[maxn]; 13 int main(){ 14 int n,m; 15 ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); 16 cin>>n; 17 ll ans=0; 18 for(int i=0;i<n;i++){ 19 cin>>m; 20 ans+=a[m]; 21 for(int j=0;j<m;j++) 22 a[j]++; 23 } 24 cout<<ans<<endl; 25 }
B.Big Water Problem
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 131072K,其他语言262144K
64bit IO Format: %lld
空间限制:C/C++ 131072K,其他语言262144K
64bit IO Format: %lld
题目描述
给一个数列,会有多次询问,对于每一次询问,会有两种操作:
1:给定两个整数x, y, 然后在原数组的第x位置上加y;
2:给定两个整数l,r,然后输出数组从第l位加到第r位数字的和并换行
输入描述:
第一行有两个整数n, m(1 <= n, m <= 100000)代表数列的长度和询问的次数
第二行n个数字,对于第i个数字a[i],(0<=a[i]<=100000)。
接下来m行,每一行有三个整数f, x, y。第一个整数f是1或者是2,代表操作类型,如果是1,接下来两个数x,y代表第x的位置上加y,如果是2,则求x到y的和,保证数据合法。
输出描述:
输出每次求和的结果并换行
示例1
输入
10 2 1 2 3 4 5 6 7 8 9 10 1 1 9 2 1 10
输出
64
这个题就是线段树的区间查询求和和单点更新。
传送3篇写的可以的线段树的博客,看完就会了(大一学的,没怎么用,就忘了,还要重新看。。。)
代码:
1 //B-线段树-区间查询求和和单点更新 2 #include<iostream> 3 #include<cstring> 4 #include<cstdio> 5 #include<cstdlib> 6 #include<algorithm> 7 using namespace std; 8 typedef long long ll; 9 #define ls l,m,rt<<1 10 #define rs m+1,r,rt<<1|1 11 #define root 1,n,1 12 const int maxn=1e5+10; 13 ll Sum[maxn<<2],Add[maxn<<2];//Sum为求和,Add为懒惰标记 14 ll A[maxn],n;//存原数组数据下标 15 16 //PushUp函数更新节点信息,这里是求和 17 void PushUp(int rt){ 18 Sum[rt]=Sum[rt<<1]+Sum[rt<<1|1]; 19 } 20 21 //下推标记的函数 22 void PushDown(int rt,int m){ 23 if(Add[rt]){//下推标记 24 Add[rt<<1]+=Add[rt]; 25 Add[rt<<1|1]+=Add[rt]; 26 Sum[rt<<1]+=Add[rt]*(m-(m>>1)); 27 Sum[rt<<1|1]+=Add[rt]*(m>>1); 28 Add[rt]=0;//清除本节点标记 29 } 30 } 31 32 //建树 33 void Build(int l,int r,int rt){//rt表示当前节点编号 34 Add[rt]=0; 35 if(l==r){ 36 Sum[rt]=A[l];return; 37 } 38 int m=(l+r)>>1; 39 Build(ls); 40 Build(rs); 41 PushUp(rt); 42 } 43 44 //区间修改A[L,R]+=C 45 //void Update(int L,int R,int C,int l,int r,int rt){ 46 // if(L<=l&&r<=R){ 47 // Sum[rt]+=(ll)C*(r-l+1); 48 // Add[rt]+=C; 49 // return ; 50 // } 51 // PushDown(rt,r-l+1);//下推标记 52 // int m=(l+r)>>1; 53 // if(L<=m)Update(L,R,C,ls); 54 // if(R>m)Update(L,R,C,rs); 55 // PushUp(rt);//更新本节点 56 //} 57 58 //点修改A[L]+=C 59 void Update(int L,int C,int l,int r,int rt){ 60 if(l==r){ 61 Sum[rt]+=C; 62 return ; 63 } 64 int m=(l+r)>>1; 65 if(L<=m)Update(L,C,ls); 66 else Update(L,C,rs); 67 PushUp(rt); 68 } 69 70 //区间查询A[L,R]的和 71 int Query(int L,int R,int l,int r,int rt){ 72 if(L<=l&&r<=R){ 73 return Sum[rt]; 74 } 75 PushDown(rt,r-l+1);//下推标记,否则Sum可能不正确 76 int m=(l+r)>>1; 77 ll ANS=0;//累计答案 78 if(L<=m)ANS+=Query(L,R,ls); 79 if(R>m)ANS+=Query(L,R,rs); 80 return ANS; 81 } 82 83 int main(){ 84 int n,m; 85 scanf("%d%d",&n,&m); 86 for(int i=1;i<=n;i++) 87 scanf("%lld",&A[i]); 88 Build(1,n,1);//建树 89 while(m--){ 90 int x; 91 scanf("%d",&x); 92 if(x==2){ 93 int a,b; 94 scanf("%d%d",&a,&b); 95 ll ANS=Query(a,b,root);//区间查询 96 printf("%lld\n",ANS); 97 } 98 else{ 99 int a,C; 100 scanf("%d%d",&a,&C); 101 Update(a,C,root);//区间修改 102 } 103 } 104 return 0; 105 }
F.The Biggest Water Problem
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 32768K,其他语言65536K
64bit IO Format: %lld
空间限制:C/C++ 32768K,其他语言65536K
64bit IO Format: %lld
题目描述
给你一个数,让他进行巴啦啦能量,沙鲁沙鲁,小魔仙大变身,如果进行变身的数不满足条件的话,就继续让他变身。。。直到满足条件为止。
巴啦啦能量,沙鲁沙鲁,小魔仙大变身:对于一个数,把他所有位上的数字进行加和,得到新的数。
如果这个数字是个位数的话,那么他就满足条件。
输入描述:
给一个整数数字n(1<=n<=1e9)。
输出描述:
输出由n经过操作满足条件的数
示例1
输入
12
输出
3
说明
12 -> 1 + 2 = 3
示例2
输入
38
输出
2
说明
38 -> 3 + 8 = 11 -> 1 + 1 = 2
这个题本来还想偷一下懒,用itoa函数写,但是我发现交上去测评姬报错,可能是不支持吧。自己手写了一个。
关于itoa,以前写过备忘:我是智障
代码:
1 //F 2 #include<iostream> 3 #include<cstring> 4 #include<cstdio> 5 #include<algorithm> 6 #include<cmath> 7 #include<queue> 8 using namespace std; 9 const int maxn=100; 10 int a[maxn]; 11 int len; 12 void itoa(int n){ 13 len=0; 14 memset(a,0,sizeof(a)); 15 while(n){ 16 a[len++]=n%10; 17 n/=10; 18 } 19 } 20 int main(){ 21 int n; 22 ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); 23 cin>>n; 24 itoa(n); 25 int tmp=0; 26 for(int i=0;i<len;i++) 27 tmp+=a[i]; 28 while(1){ 29 if(tmp>10){ 30 itoa(tmp); 31 tmp=0; 32 for(int i=0;i<len;i++) 33 tmp+=a[i]; 34 } 35 else { 36 cout<<tmp<<endl;break; 37 } 38 } 39 }
H.Tree Recovery
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 131072K,其他语言262144K
64bit IO Format: %lld
空间限制:C/C++ 131072K,其他语言262144K
64bit IO Format: %lld
题目描述
You have N integers, A1, A2, ... , AN. You need to deal with two kinds of operations. One type of operation is to add some given number to each number in a given interval. The other is to ask for the sum of numbers in a given interval.
输入描述:
输出描述:
You need to answer all Q commands in order. One answer in a line.
示例1
输入
10 5 1 2 3 4 5 6 7 8 9 10 Q 4 4 Q 1 10 Q 2 4 C 3 6 3 Q 2 4
输出
4 55 9 15
这个题是线段树区间查询求和和区间更新。
代码:
1 /* 2 //H-线段树-区间查询求和和区间更新 3 #include<iostream> 4 #include<cstring> 5 #include<cstdio> 6 #include<cstdlib> 7 #include<algorithm> 8 using namespace std; 9 typedef long long ll; 10 #define ls l,m,rt<<1 11 #define rs m+1,r,rt<<1|1 12 #define root 1,n,1 13 const int maxn=1e5+10; 14 ll Sum[maxn<<2],Add[maxn<<2];//Sum为求和,Add为懒惰标记 15 ll A[maxn],n;//存原数组数据下标 16 17 //PushUp函数更新节点信息,这里是求和 18 void PushUp(int rt){ 19 Sum[rt]=Sum[rt<<1]+Sum[rt<<1|1]; 20 } 21 22 //下推标记的函数 23 void PushDown(int rt,int m){ 24 if(Add[rt]){//下推标记 25 Add[rt<<1]+=Add[rt]; 26 Add[rt<<1|1]+=Add[rt]; 27 Sum[rt<<1]+=Add[rt]*(m-(m>>1)); 28 Sum[rt<<1|1]+=Add[rt]*(m>>1); 29 Add[rt]=0;//清除本节点标记 30 } 31 } 32 33 //建树 34 void Build(int l,int r,int rt){//rt表示当前节点编号 35 Add[rt]=0; 36 if(l==r){ 37 Sum[rt]=A[l];return; 38 } 39 int m=(l+r)>>1; 40 Build(ls); 41 Build(rs); 42 PushUp(rt); 43 } 44 45 //区间修改A[L,R]+=C 46 void Update(int L,int R,int C,int l,int r,int rt){ 47 if(L<=l&&r<=R){ 48 Sum[rt]+=(ll)C*(r-l+1); 49 Add[rt]+=C; 50 return ; 51 } 52 PushDown(rt,r-l+1);//下推标记 53 int m=(l+r)>>1; 54 if(L<=m)Update(L,R,C,ls); 55 if(R>m)Update(L,R,C,rs); 56 PushUp(rt);//更新本节点 57 } 58 59 //区间查询A[L,R]的和 60 int Query(int L,int R,int l,int r,int rt){ 61 if(L<=l&&r<=R){ 62 return Sum[rt]; 63 } 64 PushDown(rt,r-l+1);//下推标记,否则Sum可能不正确 65 int m=(l+r)>>1; 66 ll ANS=0;//累计答案 67 if(L<=m)ANS+=Query(L,R,ls); 68 if(R>m)ANS+=Query(L,R,rs); 69 return ANS; 70 } 71 72 int main(){ 73 int n,m; 74 scanf("%d%d",&n,&m); 75 for(int i=1;i<=n;i++) 76 scanf("%lld",&A[i]); 77 Build(1,n,1);//建树 78 while(m--){ 79 char str[2]; 80 scanf("%s",str); 81 if(str[0]==‘Q‘){ 82 int a,b; 83 scanf("%d%d",&a,&b); 84 ll ANS=Query(a,b,root);//区间查询 85 printf("%lld\n",ANS); 86 } 87 else{ 88 int a,b,C; 89 scanf("%d%d%d",&a,&b,&C); 90 Update(a,b,C,root);//区间修改 91 } 92 } 93 return 0; 94 } 95 */ 96 /* 97 样例 98 10 5 99 1 2 3 4 5 6 7 8 9 10 100 Q 4 4 101 Q 1 10 102 Q 2 4 103 C 3 6 3 104 Q 2 4 105 */
就这样,还有二位线段树,还没写,以后写。
滚去看搜索了,简直被虐爆了,难受。