树状数组

    树状数组有一个很牛逼的名字,叫二叉检索树,其中用O(log n)的算法可以统计前n项的和,成就了该算法的优美。

    全世界都有这个标程,贴出来看看

ContractedBlock.gif ExpandedBlockStart.gif 代码

   
1 const int maxn = ;
2   int c[maxn];
3
4   int lowbit( int x) { return x & ( - x); }
5
6   void update( int x , int delta)
7 {
8 while (x < maxn) {
9 c[x] += delta;
10 x += lowbit(x);
11 }
12 }
13
14 int sum( int x)
15 {
16 int S = 0 ;
17 while (x > 0 ) {
18 S += c[x];
19 x -= lowbit(x);
20 }
21 return S;
22 }
23
24 // 二分逼近寻找第K大,返回其下标
25 // 若寻找第K小:
26 // 1.则可以将update函数delta的值换成相反数,再找第K大
27 // 2.第K小为第K大的N - K项
28
29 int find( int k)
30 {
31 int mod = 0 , ans = 0 ;
32 for ( int i = 18 ; i >= 0 ; i -- ) {
33 ans += ( 1 << i);
34 if (mod + c[ans] >= k)
35 ans -= ( 1 << i);
36 else
37 mod += c[ans];
38 }
39 return ans + 1 ;
40 }

    POJ2299 Ultra-QuickSort

    http://acm.pku.edu.cn/JudgeOnline/problem?id=2299

    先离散化,然后逐个插入,每次插入统计前n项有多少位比他小的(不包括自己),于是最终答案为(n * (n - 1)) / 2 - s;

ContractedBlock.gif ExpandedBlockStart.gif 代码

   
1 #include < iostream >
2 #include < algorithm >
3 using namespace std;
4
5 typedef __int64 LL;
6
7 const int maxn = 500005 ;
8
9 LL a[maxn], b[maxn], c[maxn], t[maxn];
10 LL n, len;
11
12 int search(LL x)
13 {
14 int l = 0 , r = len;
15 while (l <= r)
16 {
17 // cout << l << ' ' << r << endl;
18 int m = (l + r) >> 1 ;
19 if (b[ m ] < x)
20 l = m + 1 ;
21 else if (b[ m ] > x)
22 r = m - 1 ;
23 else return m;
24 }
25 }
26
27 int lowbit( int x) { return x & ( - x); }
28
29 void modify( int x , int delta) {
30 while (x < maxn) {
31 c[x] += delta;
32 x += lowbit(x);
33 }
34 }
35
36 LL sum( int x) {
37 LL S = 0 ;
38 while (x > 0 ) {
39 S += c[x];
40 x -= lowbit(x);
41 }
42 return S;
43 }
44
45 int main()
46 {
47 while ( ~ scanf( " %d " , & n), n)
48 {
49 memset(c , 0 , sizeof (c));
50 len = 1 ;
51 for ( int i = 0 ; i < n; i ++ )
52 {
53 scanf( " %I64d " , & a[i]);
54 t[i] = a[i];
55 }
56 sort(t , t + n);
57 b[ 0 ] = t[ 0 ];
58 for ( int i = 1 ; i < n; i ++ )
59 {
60 if (t[i] != b[len - 1 ])
61 b[len ++ ] = t[i];
62 }
63 LL s = 0 , ans = (n * (n - 1 )) >> 1 ;
64 for ( int i = 0 ; i < n; i ++ )
65 {
66 int tmp = search(a[i]) + 1 ;
67 s += sum(tmp - 1 );
68 modify(tmp , 1 );
69
70 }
71 printf( " %I64d\n " , ans - s);
72 }
73 return 0 ;
74 }
75

    POJ2761 Feed the dogs

    http://acm.pku.edu.cn/JudgeOnline/problem?id=2761

    离散化,然后找第K大,速度比我的SBT快

ContractedBlock.gif ExpandedBlockStart.gif 代码

   
1 #include < iostream >
2 #include < algorithm >
3 using namespace std;
4
5 const int maxn = 500005 ;
6 int n, m, len;
7 int ans[maxn], bin[maxn], b[maxn], c[maxn], val[maxn];
8 struct NODE { int u, v, k, id; } A[maxn];
9
10 void init()
11 {
12 len = 1 ;
13 b[ 0 ] = bin[ 0 ];
14 for ( int i = 1 ; i < n; i ++ )
15 {
16 if (bin[i] != b[len - 1 ])
17 b[len ++ ] = bin[i];
18 }
19 }
20
21 int search( int x)
22 {
23 int l = 0 , r = len;
24 while (l <= r)
25 {

27 int m = (l + r) >> 1 ;
28 if (b[ m ] < x)
29 l = m + 1 ;
30 else if (b[ m ] > x)
31 r = m - 1 ;
32 else return m + 1 ;
33 }
34 }
35
36 int lowbit( int x) { return x & ( - x); }
37
38 void update( int x , int delta) {
39 while (x < maxn) {
40 c[x] += delta;
41 x += lowbit(x);
42 }
43 }
44
45 int sum( int x) {
46 int S = 0 ;
47 while (x > 0 ) {
48 S += c[x];
49 x -= lowbit(x);
50 }
51 return S;
52 }
53
54 int find( int k)
55 {
56 int cnt = 0 , ans = 0 ;
57 for ( int i = 18 ; i >= 0 ; i -- )
58 {
59 ans += ( 1 << i);
60 if (cnt + c[ans] >= k)
61 ans -= ( 1 << i);
62 else cnt += c[ans];
63 }
64 return ans + 1 ;
65 }
66
67 bool operator < ( const NODE x, const NODE y)
68 {
69 if (x.u == y.u)
70 return x.v < y.v;
71 return x.u < y.u;
72 }
73
74 int main()
75 {
76 scanf( " %d %d " , & n, & m);
77 int root = 0 ;
78 for ( int i = 1 ; i <= n; i ++ ) {
79 scanf( " %d " , & val[i]);
80 bin[i - 1 ] = val[i];
81 }
82
83 sort(bin , bin + n);
84 init();
85
86 for ( int i = 0 ; i < m; i ++ ) {
87 scanf( " %d %d %d " , & A[i].u, & A[i].v, & A[i].k);
88 if (A[i].u > A[i].v)
89 swap(A[i].u , A[i].v);
90 A[i].id = i;
91 }
92
93 sort(A, A + m);
94
95 int st = A[ 0 ].u, et = A[ 0 ].v;
96 for ( int j = st; j <= et; j ++ )
97 update(search(val[j]) , 1 );
98 ans[ A[ 0 ].id ] = find(A[ 0 ].k);
99
100 for ( int i = 1 ; i < m; i ++ ) {
101
102 if (A[i].v <= A[i - 1 ].v) {
103 for ( int j = A[i - 1 ].u; j < A[i].u; j ++ )
104 update(search(val[j]) , - 1 );
105 for ( int j = A[i].v + 1 ; j <= A[i - 1 ].v; j ++ )
106 update(search(val[j]) , - 1 );
107 st = 1 ; et = 0 ;
108 } else if (A[i].u <= A[i - 1 ].v && A[i].v >= A[i - 1 ].v) {
109 for ( int j = A[i - 1 ].u; j < A[i].u; j ++ )
110 update(search(val[j]) , - 1 );
111 st = A[i - 1 ].v + 1 ; et = A[i].v;
112 } else {
113 for ( int j = A[i - 1 ].u; j <= A[i - 1 ].v; j ++ )
114 update(search(val[j]) , - 1 );
115 st = A[i].u; et = A[i].v;
116 }
117
118 for ( int j = st; j <= et; j ++ )
119 update(search(val[j]) , 1 );
120 ans[ A[i].id ] = find(A[i].k);
121
122 }
123
124 for ( int i = 0 ; i < m; i ++ )
125 printf( " %d\n " , b[ ans[i] - 1 ]);
126 return 0 ;
127 }
128
129

 

转载于:https://www.cnblogs.com/xiao_wu/archive/2010/05/21/1741201.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值