生活随笔
收集整理的這篇文章主要介紹了
线段树+树状数组
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
感覺這東西就是每棵線段樹管的區間變了,以前學的時候線段樹總是只管一個點或者管(1-i)這些點,但是這東西如果加上樹狀數組的思想,每棵線段樹管( i-(i&-i)+1 ~ i )這些區間,那么動態修改單點就不用nlog修改只用改這個點在那log棵線段樹改log*log次;查詢的話變慢了點,之前的 log變成了 log * log;
精品博客 講的真的很好 感謝大佬:
博客園 TaylorSwift13 的 樹狀數組套權值線段樹
動態逆序對
代碼
Dynamic Rankings
代碼
#include <iostream>
#include <algorithm>
#include <cstring>
#include <sstream>
using namespace std
;
typedef long long LL
;
const int N
= 5e5 + 4;
int n
, m
;
int a
[N
], f
[N
];
int rt
[N
], ls
[N
<<6], rs
[N
<<6], val
[N
<<6], idx
= 0;namespace seg
{void modify(int &u
, int l
, int r
, int x
, int f
){if(!u
) u
= ++idx
;val
[u
] += f
;if(l
==r
)return ;int mid
= l
+r
>>1;x
<= mid
? modify(ls
[u
], l
, mid
, x
, f
) : modify(rs
[u
], mid
+1, r
, x
, f
);}int quary(int u
, int l
, int r
, int L
, int R
){if(!u
||L
>r
||R
<l
)return 0;if(L
<=l
&&R
>=r
)return val
[u
];int mid
= l
+r
>>1;return quary(ls
[u
], l
, mid
, L
, R
) + quary(rs
[u
], mid
+1, r
, L
, R
);}
};namespace tree
{int quary(int u
, int l
, int r
){int sum
= 0;for(int x
= u
;x
>= 1;x
-= (x
&-x
))sum
+= seg
::quary(rt
[x
], 0, n
+1, l
, r
);return sum
;}void modify(int u
,int g
, int f
){for(int x
= u
;x
<= n
;x
+= (x
&-x
))seg
::modify(rt
[x
], 0, n
+1, g
, f
);}
};namespace tr
{int tr
[N
]={};void modify(int u
,int f
){while(u
<=n
+1)tr
[u
]+=f
,u
+=(u
&-u
);}int quary(int u
){int sum
=0;while(u
)sum
+=tr
[u
],u
-=(u
&-u
);return sum
;}
}int main()
{scanf("%d%d",&n
, &m
);for(int i
= 1;i
<= n
;i
++)scanf("%d",a
+ i
);LL ans
= 0;for(int i
= 1;i
<= n
;i
++){ans
+= tree
::quary(i
-1, a
[i
]+1, n
+1);tree
::modify(i
, a
[i
], 1);tr
::modify(a
[i
], 1);f
[a
[i
]] = i
;}while(m
--){int x
;scanf("%d", &x
); cout
<<ans
<<endl
;ans
-= tree
::quary(f
[x
]-1, x
+1, n
+1);ans
-= tr
::quary(x
-1) - tree
::quary(f
[x
]-1, 0, x
-1);tree
::modify(f
[x
], x
, -1);tr
::modify(x
, -1);}return 0;
}
#include <iostream>
#include <algorithm>
#include <cstring>
#include <sstream>
using namespace std
;typedef long long ll
;
const int N
= 1e5 + 4;
int n
, m
;
int rt
[N
], ls
[N
<<9], rs
[N
<<9], val
[N
<<9], idx
;
int x
[N
], cntx
, y
[N
], cnty
, a
[N
];int quary(int l
, int r
, int k
)
{ if(l
== r
)return l
;int sum
= 0;for(int i
= 0;i
< cntx
;i
++)sum
-= val
[ls
[x
[i
]]];for(int i
= 0;i
< cnty
;i
++)sum
+= val
[ls
[y
[i
]]];if(sum
>= k
){for(int i
= 0;i
< cntx
;i
++)x
[i
] = ls
[x
[i
]];for(int i
= 0;i
< cnty
;i
++)y
[i
] = ls
[y
[i
]];return quary(l
, l
+r
>>1, k
);}else {for(int i
= 0;i
< cntx
;i
++)x
[i
] = rs
[x
[i
]];for(int i
= 0;i
< cnty
;i
++)y
[i
] = rs
[y
[i
]];return quary((l
+r
>>1) + 1, r
, k
- sum
);}
}void modify(int &u
, int l
, int r
, int x
, int f
)
{if(!u
)u
= ++idx
;val
[u
] += f
;if(l
== r
)return ;int mid
= l
+r
>>1;x
<= mid
? modify(ls
[u
], l
, mid
, x
, f
) : modify(rs
[u
], mid
+1, r
, x
, f
);
}int main()
{ scanf("%d%d", &n
, &m
);for(int i
= 1;i
<= n
;i
++){scanf("%d", a
+i
);for(int u
= i
;u
<= n
;u
+=(u
&-u
))modify(rt
[u
], 0, 1e9, a
[i
], 1);}while(m
--){char c
[2];int l
, r
, k
;scanf("%s%d%d", c
, &l
, &r
);if(c
[0]=='Q'){scanf("%d", &k
);cntx
= cnty
= 0;for(int j
= l
-1;j
>= 1;j
-= (j
&-j
)) x
[cntx
++] = rt
[j
];for(int u
= r
;u
>= 1; u
-= (u
&-u
)) y
[cnty
++] = rt
[u
];cout
<<quary(0, 1e9, k
)<<endl
;}else{for(int u
= l
;u
<= n
;u
+=(u
&-u
))modify(rt
[u
], 0, 1e9, a
[l
], -1);a
[l
] = r
;for(int u
= l
;u
<= n
;u
+=(u
&-u
))modify(rt
[u
], 0, 1e9, a
[l
], 1);}}return 0;
}
總結
以上是生活随笔為你收集整理的线段树+树状数组的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。