码迷,mamicode.com
首页 > 编程语言 > 详细

序列算法

时间:2019-05-02 11:27:47      阅读:149      评论:0      收藏:0      [点我收藏+]

标签:矩阵   div   bit   lowbit   \n   info   需要   区间修改   cst   

区间查询&单点修改:

给定一个序列a,进行很多次操作:
访问a[l ~~ r]的区间和;
将a[i] 的值修改为 a[i] + k;


求区间x ~~ y中的区间和:

 1 #include <cstdio>
 2 #include <algorithm>
 3 
 4 #define MAXN 2222
 5 
 6 int n, m;
 7 int a[MAXN], s[MAXN];
 8 
 9 int main() {
10     scanf("%d%d", &n, &m);
11     for(int i = 1; i <= n; i++) {
12 
13         scanf("%d", &a[i]);
14         s[i] = s[i - 1] + a[i];    //前缀和
15     }
16     for(int i = 1, x, y; i <= m; i++) {//m次操作
17         scanf("%d%d", &x, &y);
18         printf("%d\n", s[y] - s[x - 1]);//s[y] - s[x - 1]即为x ~~ y的区间和
19     }
20     return 0;
21 }
22 /*
23 10 100
24 1 9 5 6 8 7 4 3 6 9
25 */

 

树状数组:

**/*树状数组:动态维护前缀和*/**

技术图片

 1 #include<cstdio>
 2 
 3 #define lowbit(x) (x & -x)
 4 #define MAX 11111
 5                       int n,m;
 6                       int t[MAX],a[MAX];//t为树状数组
 7 
 8 void add(int x, int k) {//单点修改(向树上走)
 9     for(int i = x; i <= n; i += lowbit(i)) {
10         t[i] += k;
11     }
12 }
13 
14 int query(int x) {//区间查询(在树下向前推进)//求的是前缀和
15     int sum = 0;
16     for(int i = x; i; i -= lowbit(i)) {
17         sum += t[i];
18     }
19     return sum;
20 }
21 
22 void lineplus(const int & l , const int &r, const int &k) {
23     add(l , k);
24     add(r + 1 , -k);
25 } //区间加 & 单点查询
26 
27 int main() {
28     scanf("%d%d",&n,&m);
29     for(int i = 1; i <= n; i++) {
30         scanf("%d",&a[i]);
31         add(i , a[i]);
32     }
33     int x,y;
34     /*for(int i = 1; i <= m; i++) {
35         scanf("%d%d",&x,&y);
36         printf("%d\n",query(y) - query(x - 1));//求的是区间和(x~~y)
37     }*/
38     int k;
39     scanf("%d%d%d",&x,&y,&k);
40     lineplus(x,y,k);//x~~y区间加k
41 }
42 
43 ```
44 /*
45 5 100
46 1 4 5 6 3
47 1
48 ans:1
49 */

 

 逆序对:

 1 #include <cstdio>
 2 #include <algorithm>
 3 
 4 #define MAXN 222222
 5 
 6 using namespace std;
 7 
 8 int n, ans, tot;
 9 int a[MAXN], b[MAXN], t[MAXN];//t为树状数组,b用来离散化a
10 
11 int lowbit(int x) {
12     return x & -x;
13 }
14 
15 int query(int x) {
16     int s = 0;
17     for(int i = x; i; i -= lowbit(i)) s += t[i];
18     return s;
19 }//区间查询 返回的是前缀和
20 
21 void add(int x) {
22     for(int i = x; i <= n; i += lowbit(i)) t[i]++;
23 }
24 
25 int main() {
26     scanf("%d", &n);
27     for(int i = 1; i <= n; i++) scanf("%d", &a[i]), b[i] = a[i];//b用于去重
28 
29     //离散化:将数值转化为排名,减小取值范围
30     sort(b + 1, b + 1 + n);//先升序排个序
31     tot = 1;//第一个是不用去重的
32     printf("去重前 ");
33     for(int i = 1; i <= n; i++) printf("%d ", b[i]);//
34     for(int i = 2; i <= n; i++) if(b[i] != b[tot]) b[++tot] = b[i];//去重 ,从第二个开始
35     //补:unique()函数是一个去重函数,功能是去除相邻的重复元素(只保留一个)
36     //unique(num,mun+n)返回的是num去重后的尾地址,
37     printf("\n去重后 ");
38     for(int i = 1; i <= tot; i++) printf("%d ", b[i]);
39     for(int i = 1; i <= n; i++) a[i] = lower_bound(b + 1, b + 1 + tot, a[i]) - b;
40     //lower_bound(b + 1, b + 1 + tot, a[i])是在区间b + 1~~~b + 1 + tot中找到第一个大于等于a[i]的数,并返回它的地址
41     //所以要“- b”减b ,之后,返回的是值等于a[i]的下标(即排名) 因为b一定有a[i]  所以它就是找第一个等于a[i]的数
42     printf("\n离散化a  ");
43     for(int i = 1; i <= n; i++) printf("%d ", a[i]);
44 
45     for(int i = 1; i <= n; i++) {
46         add(a[i]);
47         int tmp = query(a[i]);
48         tmp = i - tmp;//tmp一开始是i之前的  大于i的 数 的 个数
49         ans += tmp;//逆序对的个数的和
50     }
51     printf("\n%d\n", ans);
52     return 0;
53 }
54 
55 ```
56 
57 /*
58 7
59 6 2 5 1 3 7 4
60 7
61 33 23 17 999 5 17 999
62 */

 

前缀和(二维):

 1 #include<cstdio>
 2 #include<algorithm>
 3 using namespace std;
 4 
 5 #define MAXN 1111
 6 #define MAXM 1111
 7 
 8 int n,m;//长&宽
 9 int a[MAXN][MAXM],s[MAXN][MAXM];
10 /*a为矩阵每个点的值,s[i][j]表示 以[i,j]为右下角的矩阵中(左上角为(0,0))
11 所有方格中数的和
12 */
13 int x1,y1,x2,y2;
14 /*询问的是以(x1,y1)为左上 以(x2,y2)为右下的矩阵中
15 所有方格中数的和
16 */
17 
18 int main() {
19     scanf("%d%d",&n,&m);
20     for(int i = 1; i <= n; i++) {
21         for(int j = 1; j <= m; j++) {
22             scanf("%d",&a[i][j]);
23         }
24     }
25     //初始化:
26     for(int i = 1; i <= n; i++) {
27         for(int j = 1; j <= m; j++) {
28             s[i][j] = s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1] + a[i][j];
29             //        (都是已知的)           s[i - 1][j - 1]为重复加的  然后加上他自己
30         }
31     }
32     scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
33     printf("%d",s[x2][y2] - s[x2][y1 - 1] - s[x1 - 1][y2] + s[x1 - 1][y1 - 1]);
34     // s[x1 - 1][y1 - 1] 重复减的
35     //温馨提示:画个矩阵呗
36 }

 

区间加:

给定一个序列a(初值全为0)。有很多次操作:
将a[I ~~ j]的每个值加上k
询问a[x]的值
(实际上是区间修改,单点查询问题,不过可以用差分数组改成区间查询(求p[i]的前缀和)单点修改(修改p[l],p[r + 1]的值)
差分数组的前缀和即为原数组,修改同步

代码:

 1 #include<cstdio>
 2            /* 5   2  4  4  3
 3            p:5  -3 -2  0  -1 */
 4 #define MAXN 1111
 5            int n,m;//给定序列a的长度为n,m次操作
 6            int a[MAXN],p[MAXN];//p 表示a中相邻元素的差 例:p[i] = a[i] - a[i - 1]
 7 //                 即差分
 8            int l,r,k;
 9 
10 void add(int l, int r, int k) { //加k的区间是【l , r】
11     p[l] += k;//p受影响的只有l 和 r+1 因为a[r + 1]值不变,所以p[r + 2]不变
12     p[r + 1] -= k;//只需要修改p[l] 和 p[r + 1] 的值,然后求一个前缀和就行了
13 }
14 
15 void get_a() {
16     for(int i = 1; i<= n; i++) {
17         a[i] = a[i - 1] + p[i];//相当于一维前缀和
18     }
19 }
20 
21 int main() {
22     scanf("%d%d",&n,&m);
23     for(int i = 1; i <=m; i++) {
24         scanf("%d %d %d",&l,&r,&k);
25         add(l,r,k);
26     }
27     get_a();
28     for(int i = 1; i <=n; i++) {
29         printf("%d ",a[i]);
30     }
31 }

 

序列算法

标签:矩阵   div   bit   lowbit   \n   info   需要   区间修改   cst   

原文地址:https://www.cnblogs.com/virtualtan/p/10801626.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!