Dynamic Inversions 50个树状数组

Dynamic Inversions

Time Limit: 30000/15000MS (Java/Others) Memory Limit: 128000/64000KB (Java/Others)

SubmitStatus

Problem Description

给出N个数a[1],a[2] ... a[N],有M个操作,每个操作给出x,y两个数,你将a[x],a[y]交换,然后求交换后数组的逆序对个数。
逆序对的意思是1 <= i < j <= N 且a[i] > a[j].

Input

多组数据,每组数据:

一个N,接下来一行有N个数a[1]... a[N]

再下去一行是M,最后M行每行两个数x,y

1 <= N,M <= 10^5, 1 <= x,y <= N,1 <= a[i] <= 50

Output

对于每组数据,输出M + 1行,第一行是开始时的逆序对数目,接下去M行每行一个数,表示这次修改后的逆序对数目

Sample Input

2
1 2
1
2 1
3
1 2 3
3
1 2
2 3
3 1

Sample Output

0
1
0
1
2
1

Hint

第二个样例,一开始1 2 3,逆序对数为0,交换第1,2个元素,变为2 1 3,答案为1,交换第2和3个元素,变为2 3 1,逆序对数为2,交换第3和1个元素,逆序对数为1,此时序列变成1 3  2

二维树状数组做法:

 1 #include <iostream>
 2 #include <stdio.h>
 3 #include <string.h>
 4 #include <math.h>
 5 #include <algorithm>
 6 using namespace std;
 7 #define ll long long
 8 int b[60][100100],a[100100],n,c[60];
 9 int lowbit(int x)
10 {
11     return x&(-x);
12 }
13 void update1(int x)
14 {
15     while(x<60)
16     {
17         c[x]++;
18         x+=lowbit(x);
19     }
20 }
21 int query1(int x)
22 {
23     int sum=0;
24     while(x>0)
25     {
26         sum+=c[x];
27         x-=lowbit(x);
28     }
29     return sum;
30 }
31 void update(int x,int y,int z)
32 {
33     for(int i=x; i<=50; i+=lowbit(i))
34         for(int j=y; j<=n; j+=lowbit(j))
35             b[i][j]+=z;
36 }
37 int query(int x,int y,int x1,int y1)
38 {
39     int ans=0,i,j;
40     for(i=y;i>0;i-=lowbit(i))
41     for(j=y1;j>0;j-=lowbit(j))
42     ans+=b[i][j];
43
44     for(i=x-1;i>0;i-=lowbit(i))
45     for(j=y1;j>0;j-=lowbit(j))
46     ans-=b[i][j];
47
48     for(i=y;i>0;i-=lowbit(i))
49     for(j=x1-1;j>0;j-=lowbit(j))
50     ans-=b[i][j];
51
52     for(i=x-1;i>0;i-=lowbit(i))
53     for(j=x1-1;j>0;j-=lowbit(j))
54     ans+=b[i][j];
55     return ans;
56 }
57 int main()
58 {
59     int i,m,x,y;
60     ll ans;
61     while(~scanf("%d",&n))
62     {
63         ans=0;
64         memset(b,0,sizeof(b));
65         memset(c,0,sizeof(c));
66         for(i=1; i<=n; i++)
67         {
68             scanf("%d",&a[i]);
69             update1(a[i]);
70             ans+=i-query1(a[i]);
71             update(a[i],i,1);
72         }
73         printf("%lld\n",ans);
74         scanf("%d",&m);
75         for(i=0; i<m; i++)
76         {
77             scanf("%d%d",&x,&y);
78             if(x>y)swap(x,y);
79             ans-=query(a[y]+1,50,x+1,y);
80             ans+=query(1,a[y]-1,x+1,y);
81             ans+=query(a[x]+1,50,x,y-1);
82             ans-=query(1,a[x]-1,x,y-1);
83             if(a[x]>a[y])ans--;
84             else if(a[x]<a[y])ans++;
85             update(a[x],x,-1);
86             update(a[x],y,1);
87             update(a[y],y,-1);
88             update(a[y],x,1);
89              swap(a[x],a[y]);
90             printf("%lld\n",ans);
91         }
92     }
93 }

50个一维的做法:

 1 #include <iostream>
 2 #include <stdio.h>
 3 #include <string.h>
 4 #include <math.h>
 5 #include <algorithm>
 6 using namespace std;
 7 #define ll long long
 8 int a[51][100010],b[60],n,c[60];
 9 int lowbit(int x)
10 {
11     return x&(-x);
12 }
13 int update(int x)
14 {
15     while(x<60)
16     {
17         b[x]++;
18         x+=lowbit(x);
19     }
20 }
21 int update1(int i,int x,int y)
22 {
23     while(x<=n)
24     {
25         a[i][x]+=y;
26         x+=lowbit(x);
27     }
28 }
29 int query(int x)
30 {
31     int sum=0;
32     while(x>0)
33     {
34         sum+=b[x];
35         x-=lowbit(x);
36     }
37     return sum;
38 }
39 int query1(int i,int x)
40 {
41     int sum=0;
42     while(x>0)
43     {
44         sum+=a[i][x];
45         x-=lowbit(x);
46     }
47     return sum;
48 }
49 int main()
50 {
51     int i,j,m,x,y,z;
52     ll ans,temp,temp1;
53     while(~scanf("%d",&n))
54     {
55         memset(b,0,sizeof(b));
56         memset(a,0,sizeof(a));
57         memset(c,0,sizeof(c));
58         ans=0;
59         for(i=1; i<=n; i++)
60         {
61             scanf("%d",&a[0][i]);
62             c[a[0][i]]++;
63             ans+=i-query(a[0][i])-1;
64             update(a[0][i]);
65             update1(a[0][i],i,1);
66         }
67         printf("%lld\n",ans);
68         scanf("%d",&m);
69         for(i=0; i<m; i++)
70         {
71             scanf("%d%d",&x,&y);
72             if(x>y)swap(x,y);
73             z=y-x;
74             temp=0;
75             for(j=1; j<a[0][y]; j++)
76             {
77                 temp+=query1(j,y-1)-query1(j,x-1);
78             }
79             temp1=query1(j,y-1)-query1(j,x-1);
80             ans+=temp-(z-temp1-temp);
81             temp=0;
82             for(j=1; j<a[0][x]; j++)
83             {
84                 temp+=query1(j,y-1)-query1(j,x-1);
85             }
86             temp1=query1(j,y-1)-query1(j,x-1);
87             ans+=(z-temp1-temp)-temp;
88             update1(a[0][x],x,-1);
89             update1(a[0][x],y,1);
90             update1(a[0][y],y,-1);
91             update1(a[0][y],x,1);
92             swap(a[0][y],a[0][x]);
93             printf("%lld\n",ans);
94         }
95     }
96 }

Dynamic Inversions 50个树状数组

时间: 2024-10-13 05:35:23

Dynamic Inversions 50个树状数组的相关文章

Swaps and Inversions HDU - 6318 树状数组+离散化

#include<iostream> #include<algorithm> #include<cstring> #include<cstdio> using namespace std; typedef long long ll; const int N=1e5+10; int a[N]; int ra[N]; int tr[N]; int n,x,y; int sz; int lowbit(int x) { return x&-x; } void

Dynamic Inversions II 逆序数的性质 树状数组求逆序数

Dynamic Inversions II Time Limit: 6000/3000MS (Java/Others) Memory Limit: 128000/64000KB (Java/Others) SubmitStatus Problem Description 给出N个数a[1],a[2] ... a[N],a[1]...a[N]是1-N的一个排列,即1 <= a[i] <= N且每个数都不相同.有M个操作,每个操作给出x,y两个数,你将a[x],a[y]交换,然后求交换后数组的逆序

ZOJ 2112 Dynamic Rankings(树状数组+主席树)

The Company Dynamic Rankings has developed a new kind of computer that is no longer satisfied with the query like to simply find the k-th smallest number of the given N numbers. They have developed a more powerful system such that for N numbers a[1],

HDU5196--DZY Loves Inversions 树状数组 逆序数

题意查询给定[L, R]区间内 逆序对数 ==k的子区间的个数. 我们只需要求出 子区间小于等于k的个数和小于等于k-1的个数,然后相减就得出答案了. 对于i(1≤i≤n),我们计算ri表示[i,ri]的逆序对数小于等于K,且ri的值最大.(ri对应代码中的cnt数组) 显然ri单调不降,我们可以通过用两个指针扫一遍,利用树状数组计算出r数组. 对于每个询问L,R,我们要计算的是∑i=LR[min(R,ri)−i+1] 由于ri具有单调性,那我们直接在上面二分即可,然后记一个前缀和(s数组).

【BZOJ1901】Dynamic Rankings,树状数组套主席树

Time:2016.05.09 Author:xiaoyimi 转载注明出处谢谢 传送门(权限) 题面 1901: Zju2112 Dynamic Rankings Time Limit: 10 Sec Memory Limit: 128 MB Submit: 6678 Solved: 2777 [Submit][Status][Discuss] Description 给定一个含有n个数的序列a[1],a[2],a[3]--a[n],程序必须回答这样的询问:对于给定的i,j,k,在a[i],a

bzoj 1901: Zju2112 Dynamic Rankings -- 主席树,树状数组,哈希

1901: Zju2112 Dynamic Rankings Time Limit: 10 Sec  Memory Limit: 128 MB Description 给定一个含有n个数的序列a[1],a[2],a[3]……a[n],程序必须回答这样的询问:对于给定的i,j,k,在a[i],a[i+1 ],a[i+2]……a[j]中第k小的数是多少(1≤k≤j-i+1),并且,你可以改变一些a[i]的值,改变后,程序还能针对改 变后的a继续回答上面的问题. Input 第一行有两个正整数n(1≤

P2617 Dynamic Rankings(主席树+树状数组)

怕是还没有题解,所以先写一篇. 这题就是维护带修改的主席树.首先树套树肯定是能做的,既然树套树能做那么整体二分肯定也是可以的. 由于我并没有使用这两种做法,所以此处不予介绍. 大概描述下主席树的思路: 首先说说怎么搞带修改主席树? 回忆一般的kth问题,我们的主席树求的是前缀和,这样我们在目标区间的左右端点的主席树差分下就能求出kth. 那么我们如何支持修改操作? 考虑到我们之前使用主席树朴素的维护区间前缀和,支持修改的话,只要把前缀和交给擅长它的树状数组维护,主席树只要维护下位置就好. 1 #

UVA 11990 `Dynamic&#39;&#39; Inversion CDQ分治, 归并排序, 树状数组, 尺取法, 三偏序统计 难度: 2

题目 https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=3141 题意 一个1到n的排列,每次随机删除一个,问删除前的逆序数 思路 综合考虑,对每个数点,令value为值,pos为位置,time为出现时间(总时间-消失时间),明显是统计value1 > value2, pos1 < pos2, time1 < time2的个

P2617 Dynamic Rankings (动态开点权值线段树 + 树状数组)

题意:带修求区间k小 题解:回忆在使用主席树求区间k小时 利用前缀和的思想 既然是前缀和 那么我们可以使用更擅长维护前缀和的树状数组 但是这里每一颗权值线段树就不是带版本的 而是维护数组里i号点的权值信息 所以实际上并不是主席树 每一棵和前面一棵并没有共用结点 对于一次修改操作 我们先删去这个点的原信息 再更新进去 树状数组上的点一起跳 可能看代码比较好理解一点 这个方法限制性也很强 必须离线 #include <bits/stdc++.h> using namespace std; cons