线段树——单点更新(二)
HDU 4217 Data Structure??
http://acm.hdu.edu.cn/showproblem.php?pid=4217
CZ做的一道題目,我幫忙看了看。
題意:給定N個數(1---N),K個操作,然后給K數,i1,i2,i3.......ik 每次取走當前狀態下等的第i個數(從小到大的),問取走的數的和。
給的那個的n為262144可以斷定肯定是O(n*log(n))級的算法,所以選定線段樹。
葉子節點賦值為1,這些節點存儲的就是數的個數,在添加一個val數組記錄是哪個數。每次更新將節點a[rt]變成0,找出對應的val[rt]即可。
這里坑爹的地方時sum求和時,要用—int64.wa了很多次才發現。
View Code #include <iostream> #include <cstring> #include <cstdio> #define maxn 262145 using namespace std;int a[maxn*4],val[maxn*4]; int tmp; __int64 sum;void pushup(int rt) {a[rt] = a[rt<<1] + a[rt<<1|1]; } void build(int l,int r,int rt) {if (l == r){a[rt] = 1;val[rt] = ++tmp;return ;}int m = (l + r)>>1;build(l,m,rt<<1);build(m + 1,r,rt<<1|1);pushup(rt); } void update(int sc,int l,int r,int rt) {if (l == r){a[rt] = 0;sum += val[rt];return ;}int m = (l + r)>>1;if (sc <= a[rt<<1]) update(sc,l,m,rt<<1);else{sc -= a[rt<<1];update(sc,m + 1,r,rt<<1|1);}pushup(rt); } int main() {int n,q,t,c;int cas = 1;scanf("%d",&t);while (t--){for (int i = 0; i < 4*maxn; ++i) a[i] = val[i] = 0;tmp = 0;scanf("%d%d",&n,&q);sum = 0;build(1,n,1);while (q--){scanf("%d",&c);update(c,1,n,1);}printf("Case %d: %I64d\n",cas++,sum);}return 0; }?
?hdu 4263?Juggler
http://acm.hdu.edu.cn/showproblem.php?pid=4262
題意:
可以把本題理解成一個佛珠在手里轉,可以順時針也可以逆時針,每次將手中的佛珠扣下來扔掉,給出每個佛珠扔出去的順序,每移動一個佛珠或者扔掉一個佛珠就要耗時1s最小耗時。
思路:
單純的模擬是O(n^2)的復雜度,肯定會超時,這里我們用線段樹來維護,葉子節點0/1表示該點是否被移除,當訪問當前點與要被刪除的點的相對位置時,我們用線段樹區間和來求,扔出后單點更新,訪問下一個到達手中的點時,getpos來求。這里主要是循環圈不好想。。傷腦筋。。
View Code #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <queue> #include <stack> #include <set> #include <map> #include <string>#define CL(a,num) memset((a),(num),sizeof(a)) #define iabs(x) ((x) > 0 ? (x) : -(x)) #define Min(a,b) (a) > (b)? (b):(a) #define Max(a,b) (a) > (b)? (a):(b)#define ll __int64 #define inf 0x7f7f7f7f #define MOD 1000000007ll #define lc l,m,rt<<1 #define rc m + 1,r,rt<<1|1 #define pi acos(-1.0) #define test puts("<------------------->") #define maxn 100010 #define N 1000005 #define M 200007 using namespace std;int val[maxn<<2]; int pos[maxn];void pushup(int rt) {val[rt] = val[rt<<1] + val[rt<<1|1]; } void build(int l,int r,int rt) {if (l == r){val[rt] = 1;return ;}int m = (l + r)>>1;build(lc);build(rc);pushup(rt); } void update(int pos,int l,int r,int rt) {if (l == r){val[rt] = 0;return ;}int m = (l + r)>>1;if (pos <= m) update(pos,lc);else update(pos,rc);pushup(rt); } int query(int L,int R,int l,int r,int rt) {if (l >= L && r <= R) return val[rt];int res = 0;int m = (l + r)>>1;if (L <= m) res += query(L,R,lc);if (R > m) res += query(L,R,rc);return res; } int getpos(int s,int l,int r,int rt) {if (l == r) return l;int m = (l + r)>>1;if (s <= val[rt<<1]) return getpos(s,lc);else{s -= val[rt<<1];return getpos(s,rc);} } int main() {//freopen("din.txt","r",stdin);int n,i,a;while (~scanf("%d",&n)){if (!n) break;for (i = 1; i <= n; ++i){scanf("%d",&a);pos[a] = i;//標記第a個被扔出去的編號 }build(1,n,1);int curpos = 1;//當前在手中的點的標號ll ans = 0;for (i = 1; i <= n; ++i){int tmp = 0;if (curpos == pos[i]) ans += 1;//只剩一個點了else if (curpos < pos[i])//1 2 3 4 5; 3要被刪除 {tmp = query(curpos + 1,pos[i],1,n,1);ans += (min(tmp,n - i + 1 - tmp) + 1);//n - i + 1 - tmp就是順時針的個數了,這里比賽時寫麻煩了 }else//同理 {tmp = query(pos[i],curpos - 1,1,n,1);ans += (min(tmp,n - i + 1 - tmp) + 1);}//printf(">>%d %d %d %d\n",tmp,n - i + 1 - tmp,Min(tmp,n - i + 1 - tmp),(Min(tmp,n - i + 1 - tmp) + 1));//這里發現了用宏定義的Min不行出錯update(pos[i],1,n,1);int s = query(1,pos[i],1,n,1);if (s < n - i)//如果pos[i]后面還有未被刪除的點curpos = getpos(s + 1,1,n,1);else//如果沒有就找第一個未被刪除的點curpos = getpos(1,1,n,1);}printf("%I64d\n",ans);}return 0; }?1006 hdu 4325?http://acm.hdu.edu.cn/showproblem.php?pid=4325
http://www.cnblogs.com/E-star/archive/2012/08/01/2619066.html
pku?Sliding Window?http://poj.org/problem?id=2823
題解:http://www.cnblogs.com/E-star/archive/2012/08/26/2657596.html
?
?
轉載于:https://www.cnblogs.com/E-star/archive/2012/07/22/2603493.html
總結
以上是生活随笔為你收集整理的线段树——单点更新(二)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: HDU 2546 饭卡(贪心+DP)
- 下一篇: glut实现动画