数据结构:线段树(树状数组、BST、LCA、
2018-02-09 17:22
525 查看
2018.2.5 - 2018.2.9
跟着idy002大佬学习的这几天。重点线段树、树状数组(各种修改和查询、树链剖分、BST(旋转跳跃我闭着眼、离散化、LCA以及一些指针的基本用法。(还有单调栈和队列什么的就不列了
简直比老李讲一个月还有用
线段树树状数组掌握的还行,但是没有办法一次过aaa,每次调试都要调几个小时???(天天练也没有办法不学好吧…
线段树多个标记:
树状数组维护区间:
BST旋转:(至今超时找不出原因就只能贴idy大佬的了
(他的板子真的好好看aaa可是背不下来…
倍增找LCA:
树链剖分找LCA:
以及今天的:
可是还是没有懂离散化扫描线…
以上都是板子,具体题目具体分析。
继续努力!(下周数论我可以go die了
跟着idy002大佬学习的这几天。重点线段树、树状数组(各种修改和查询、树链剖分、BST(旋转跳跃我闭着眼、离散化、LCA以及一些指针的基本用法。(还有单调栈和队列什么的就不列了
简直比老李讲一个月还有用
线段树树状数组掌握的还行,但是没有办法一次过aaa,每次调试都要调几个小时???(天天练也没有办法不学好吧…
线段树多个标记:
#include<iostream> #include<cstdio> using namespace std ; #define p 1000000007 const int N = 100005; struct node { long long a, b ; };node tag[N*4] ; long long sum[N*4] ; int n, aa ; void update ( int rt ) { sum[rt] = (sum[rt << 1] + sum[(rt << 1) + 1]) % p ; } int flag[N*4]; void push_down ( int rt, int l, int r ) { int mid = (l + r) >> 1; if ( flag[rt] ) { tag[rt << 1 ].a = ( tag[rt].a * tag[rt << 1].a ) % p ; tag[(rt << 1) + 1].a = ( tag[rt].a * tag[(rt << 1) + 1].a ) % p ; tag[rt << 1].b = (( tag[rt].a * tag[rt << 1].b) % p + tag[rt].b ) % p ; tag[(rt << 1) + 1].b = (( tag[rt].a * tag[(rt << 1) + 1].b ) % p + tag[rt].b ) % p ; sum[rt << 1] = (((sum[rt << 1]) * tag[rt].a ) % p + (tag[rt].b * (mid - l + 1) % p )) %p ; sum[(rt << 1) + 1] = ((sum[(rt << 1) + 1] *tag[rt].a ) % p + tag[rt].b * (r - mid ) %p ) % p ; tag[rt].a = 1; tag[rt].b = 0; flag[rt] = 0; flag[rt << 1] = flag[(rt << 1) + 1] = 1; } } void build ( int rt, int l, int r ) { tag[rt].a = 1 ; tag[rt].b = 0 ; if ( l == r ) sum[rt] = aa[l]; else { int mid = (l + r) >> 1 ; build ( rt << 1, l, mid ) ; build ( (rt << 1) + 1, mid + 1, r ) ; update ( rt ) ; } sum[rt] %= p ; } void add ( int A, int B, int L, int R, const int lf, const int rg,int rt ) { if ( L >= lf && R <= rg ) { tag[rt].b = ((A * tag[rt].b)%p + B) % p ;//太恶心了*的地方不加mod就会爆,少写一个检查5小时 tag[rt].a = (A * tag[rt].a) % p ; sum[rt] = (A * sum[rt] + 1LL * B * (R - L + 1)) %p ; flag[rt] = 1 ; return ; } push_down ( rt, L, R ) ; int mid = (L + R) >> 1; if ( mid >= lf ) add ( A, B, L, mid, lf, rg, rt << 1 ) ; if ( mid < rg ) add ( A, B, mid + 1, R, lf, rg, (rt << 1) + 1 ) ; update ( rt ) ; } long long query ( int rt, int L, int R, int lf, int rg ) { if ( L >= lf && R <= rg ) { return sum[rt]% p ; } push_down ( rt, L, R ) ; int mid = (L + R) >> 1; long long ans = 0 ; if ( mid >= lf ) ans = (ans + (query ( rt << 1, L, mid, lf, rg )) % p) % p; if ( mid < rg ) ans = (ans + (query ( (rt << 1) + 1, mid + 1, R, lf, rg )) % p) % p ; return ans % p ; } int main ( ) { freopen ("linear.in","r",stdin); freopen ("linear.out","w",stdout); scanf ( "%d", &n ) ; for ( int i = 1; i <= n; i ++ ) scanf ( "%d", &aa[i] ) ; build ( 1, 1, n ) ; int q; scanf ( "%d", &q ) ; for ( int i = 1; i <= q; i ++ ) { char s[10]; scanf ( "%s", s ) ; if ( s[0] == 'q' ) { int x, y; scanf ( "%d%d", &x, &y ) ; printf ( "%I64d\n", query ( 1,1,n,x,y ) ) ; } else { int x, y, A, B ; scanf ( "%d%d%d%d", &x, &y, &A, &B ) ; add ( A, B, 1, n, x, y, 1 ) ; } } return 0 ; }
树状数组维护区间:
#include<iostream> #include<cstdio> using namespace std ; const int N = 100005 ; int n, a ; long long pre ; int lowbit ( int x ) { return x & (-x) ; } void add ( int x, int d ) { for ( int i = x; i <= n; i += lowbit(i) ) pre[i] += d ; } long long query ( int x ) { long long sum = 0 ; for ( int i = x; i; i -= lowbit(i) ) sum += pre[i] ; return sum ; } int main ( ) { freopen ( "bit.in","r",stdin ) ; freopen ( "bit.out","w",stdout ) ; scanf( "%d", &n ) ; for ( int i = 1; i <= n; i ++ ) { scanf ( "%d", &a[i] ) ; add ( i,a[i]-a[i-1]) ;//作差 } int q ; scanf ( "%d", &q ) ; 12360 for ( int i = 1; i <= q; i ++ ) { char s [10] ; scanf ( "%s", s ) ; if ( s[0] == 'q' ) { int x; scanf ( "%d", &x ) ; printf ( "%I64d\n", query(x) ) ; } else { int x, y, d; scanf ( "%d%d%d", &x, &y, &d ) ; add ( x, d ) ; add ( y + 1, -d ) ; } } return 0 ; }
BST旋转:(至今超时找不出原因就只能贴idy大佬的了
struct Splay { int pre[maxn], son[maxn][2], val[maxn], siz[maxn], ntot, root; void update( int nd ) { siz[nd] = siz[son[nd][0]]+siz[son[nd][1]]+1; } int build( int p, int *a, int lf, int rg ) { if( lf>rg ) return 0; int nd = ++ntot; int mid = (lf+rg)>>1; pre[nd] = p; son[nd][0] = build( nd, a, lf, mid-1 ); son[nd][1] = build( nd, a, mid+1, rg ); val[nd] = a[mid]; update( nd ); return nd; } void init( int n, int *a ) { siz[0] = 0; root = build( 0, a, 1, n ); } void rotate( int nd, int d ) { int p = pre[nd]; int s = son[nd][!d]; int ss = son[s][d]; son[nd][!d] = ss; son[s][d] = nd; if( p ) son[p][ nd==son[p][1] ] = s; else root = s; pre[nd] = s; pre[s] = p; if( ss ) pre[ss]=nd; update(nd); update(s); } void splay( int nd, int top=0 ) { while( pre[nd]!=top ) { int p = pre[nd]; int nl = nd==son[p][0]; if( pre[p]==top ) { rotate( p, nl ); } else { int pp = pre[p]; int pl = p==son[pp][0]; if( nl==pl ) { rotate( pp, pl ); rotate( p, nl ); } else { rotate( p, nl ); rotate( pp, pl ); } } } } int find( int pos ) { int nd=root; while(1) { int ls = siz[son[nd][0]]; if( pos<=ls ) nd=son[nd][0]; else if( pos>=ls+2 ) { pos -= ls+1; nd=son[nd][1]; } else return nd; } } void erase( int pos ) { int lnd = find(pos-1); int rnd = find(pos+1); splay( lnd ); splay( rnd, lnd ); son[rnd][0] = 0; update( rnd ); update( lnd ); } int query( int pos ) { return val[find(pos)]; } }; Splay T;
(他的板子真的好好看aaa可是背不下来…
倍增找LCA:
//也是idy的 #include <iostream> using namespace std; const int N = 200000 + 10; const int P = 20; int n, root; int head , dest , last , etot; int anc [P+1], dep ; void dfs(int u, int f) { anc[u][0] = f; for(int p = 1; p <= P; p++) anc[u][p] = anc[anc[u][p-1]][p-1]; for(int t = head[u]; t; t = last[t]) { int v = dest[t]; if(v == f) continue; dep[v] = dep[u] + 1; dfs(v, u); } } int lca(int u, int v) { // 调到深度相同 if(dep[u] < dep[v]) swap(u,v); int t = dep[u] - dep[v]; for(int p = 0; t; t>>=1,p++) if(t & 1) u = anc[u][p]; if(u == v) return u; // 一起跳,直到跳到lca的下面 for(int p = P; p >= 0; p--) if(anc[u][p] != anc[v][p]) u = anc[u][p], v = anc[v][p]; return anc[u][0]; } int main() { dep[root] = 1; dfs(root, root); } /* 求2n-1的dfs序,用于O(1)求 lca N 是 树节点的两倍 */ /* #include <iostream> using namespace std; const int N = 200000 + 10; const int P = 20; int n, root; int head , dest , last , etot; int stu [P+1]; int pos , dep , seq , idc; int logb ; void dfs(int u, int f) { for(int t = head[u]; t; t = last[t]) { int v = dest[t]; if(v == f) continue; seq[++idc] = v; pos[v] = idc; dep[v] = dep[u] + 1; dfs(v, u); seq[++idc] = u; pos[u] = idc; } } void init() { logb[0] = -1; for(int i = 1; i < N; i++) logb[i] = logb[i>>1] + 1; for(int p = 0; p <= P; p++) { for(int i = 1; i + (1<<p) - 1 <= idc; i++) { if(p == 0) { stu[i][p] = seq[i]; } else { int l = stu[i][p-1], r = stu[i+(1<<(p-1))][p-1]; stu[i][p] = (dep[l] < dep[r]) ? l : r; } } } } int lca(int u, int v) { u = pos[u], v = pos[v]; if(u > v) swap(u,v); int len = v - u + 1; int p = logb[len]; int uu = stu[u][p]; int vv = stu[v - (1<<p) + 1][p]; return dep[uu] < dep[vv] ? uu : vv; } int main() { init(); idc = 0; seq[++idc] = root; dep[root] = 1; dfs(root, root); } */
树链剖分找LCA:
#include<iostream> #include<cstdio> using namespace std; const int N = 100005 ; const int P = 20 ; int n ; int head[N*2], tov[N*2], nex[N*2], stot ; void adde ( int u, int v ) { tov[++stot] = v ; nex[stot] = head[u] ; head[u] = stot ; } int dep , anc , ch , child , fat ;//当时多开了一个5M的倍增用的二维数组秒超空间,100分灰飞烟灭!!! void dfs1 ( int u, int f ) { child[u] = 1; for ( int i = head[u]; i; i = nex[i] ) { int v = tov[i] ; if ( v == f ) continue ; dep[v] = dep[u] + 1 ; fat[v] = u ; dfs1 ( v, u ) ; child[u] += child[v] ; if ( child[v] > child[ch[u]] ) ch[u] = v ; } } int tp, top ; void dfs2 ( int u, int f ) { top[u] = f ; if ( ch[u] ) dfs2 ( ch[u], f ) ; for( int i = head[u]; i; i = nex[i] ) { int v = tov[i] ; if ( v == ch[u] || v == fat[u] ) continue; dfs2 ( v, v ) ; } } int lca ( int u, int v ) { while ( top[u] != top[v] ) { if ( dep [top[u]] < dep [top[v]] ) swap ( u, v ) ; u = fat[top[u]] ; } return dep[u] < dep[v] ? u : v ; } int main ( ) { freopen( "dcplca.in","r",stdin ) ; freopen( "dcplca.out","w",stdout ) ; scanf ( "%d", &n ) ; for ( int i = 1; i < n; i ++ ) { int u, v ; scanf ( "%d%d", &u, &v ) ; adde ( u, v ) ; adde ( v, u ) ; } int q, u, v ; dep[1] = 1 ; fat[1] = 1 ; dfs1 ( 1, 1 ) ; dfs2 ( 1, 1 ) ; scanf ( "%d", &q ) ; for ( int i = 1; i <= q; i ++ ) { scanf ( "%d%d", &u, &v ) ; int ans = lca ( u, v ) ; printf ( "%d\n", ans ) ; } return 0 ; }
以及今天的:
// 可持久化数组 struct Node { int v; Node *ls, *rs; }pool[N*32], *tail=pool, *root ; Node *build(int lf, int rg) { Node *nd = ++tail; if(lf == rg) { nd->v = aa[lf]; } else { int mid = (lf + rg) >> 1; nd->ls = build(lf, mid); nd->rs = build(mid+1, rg); } return nd; } int query(Node *nd, int lf, int rg, int pos) { if(lf == rg) { return nd->v; } int mid = (lf + rg) >> 1; if(pos <= mid) return query(nd->ls, lf, mid, pos); if(pos > mid) return query(nd->rs, mid+1, rg, pos); } Node * modify(Node *nd, int lf, int rg, int pos, int val) { Node *nnd = ++tail; if(lf == rg) { nnd->v = val; return nnd; } int mid = (lf + rg) >> 1; if(pos <= mid) { nnd->ls = modify(nd->ls, lf, mid, pos, val); nnd->rs = nd->rs; } else { nnd->ls = nd->ls; nnd->rs = modify(nd->rs, mid+1, rg, pos, val); } return nnd; } Node * modify(Node *nd, int pos, int val) { return modify(nd, 1, n, pos, val); } Node * print(Node *nd, int pos) { printf("%d\n", query(nd, 1, n, pos)); return nd; } Node * back(int t) { return root[t]; } int main() { root[0] = build(1, n); for(int i = 1; i <= q; i++) { root[i] = modify(root[i-1], pos, val); // modify root[i] = print(root[i-1], pos); // print root[i] = back(t); // back } } // 动态开节点 struct Node { int sum; Node *ls, *rs; void update() { sum = ls->sum + rs->sum; } }pool[N*32], *tail=pool, *zero, *root; Node *newnode(int val) { Node *nd = ++tail; nd->ls = nd->rs = zero; nd->sum = val; return nd; } void build() { zero = ++tail; zero->ls = zero->rs = zero; zero->sum = 0; root = newnode(0); } int query(Node *nd, int lf, int rg, int L, int R) { if(nd == zero) return 0; if(L<= lf && rg <= R) return nd->sum; int mid = (lf + rg) >> 1; int rt = 0; if(L <= mid) rt += query(nd->ls, lf, mid, L, R); if(R > mid) rt += query(nd->rs, mid+1, rg, L, R); return rt; } void modify(Node *nd, int lf, int rg, int pos, int val) { if(lf == rg) { nd->sum = val; return; } int mid = (lf + rg) >> 1; if(pos <= mid) { if(nd->ls == zero) { nd->ls = newnode(0); } modify(nd->ls, lf, mid, pos, val); } else { if(nd->rs == zero) { nd->rs = newnode(0); } modify(nd->rs, mid+1, rg, pos, val); } nd->update(); } // 区间第k大 struct Node { int cnt; Node *ls, *rs; void update() { cnt = ls->cnt + rs->cnt; } }pool[N*32], *tail=pool, *zero, *root ; int n; int aa ; Node *newnode() { Node *nd = ++tail; nd->ls = nd->rs = zero; nd->cnt = 0; return nd; } void build() { zero = ++tail; zero->ls = zero->rs = zero; zero->cnt = 0; root[0] = newnode(); } int query(Node *nd, int lf, int rg, int L, int R) { if(nd == zero) return 0; if(L <= lf && rg <= R) { return nd->cnt; } int mid = (lf + rg) >> 1; int rt = 0; if(L <= mid) rt += query(nd->ls, lf, mid, L, R); if(R > mid) rt += query(nd->rs, mid+1, rg, L, R); return rt; } Node * modify(Node *nd, int lf, int rg, int pos, int delta) { Node *nnd = ++tail; if(lf == rg) { nnd->cnt = nd->cnt + delta; return nnd; } int mid = (lf + rg) >> 1; if(pos <= mid) { nnd->ls = modify(nd->ls, lf, mid, pos, delta); nnd->rs = nd->rs; } else { nnd->ls = nd->ls; nnd->rs = modify(nd->rs, mid+1, rg, pos, delta); } nnd->update(); return nnd; } int query(Node *lnd, Node *rnd, int lf, int rg, int k) { if(lf == rg) return lf; int mid = (lf + rg) >> 1; int lz = rnd->ls->cnt - lnd->ls->cnt; if(k <= lz) return query(lnd->ls, rnd->ls, lf, mid, k); else return query(lnd->rs, rnd->rs, mid+1, rg, k - lz); } int query(int lf, int rg, int k) { return query(root[lf-1], root[rg], 1, n, k); } int main() { build(); for(int i = 1; i <= n; i++) { root[i] = modify(root[i-1], 1, n, aa[i], +1); } printf("%d\n", query(1,5,3)); } // 离散化 int n; int xx , yy ; int disc , dtot; int main() { for(int i = 1; i <= n; i++) { disc[++dtot] = xx[i]; disc[++dtot] = yy[i]; } sort(disc+1, disc+1+dtot); dtot = unique(disc+1, disc+1+dtot) - disc - 1; int i = lower_bound(disc+1, disc+1+dtot, 23) - disc; } // 扫描线 struct Node { int cnt; int sum; Node *ls, *rs; void update(int lf, int rg) { if(cnt) sum = rg - lf + 1; else sum = ls->sum + rs->sum; } }pool[N*2], *tail=pool, *root; void modify(Node *nd, int lf, int rg, int L, int R, int delta) { if(L <= lf && rg <= R) { nd->cnt += delta; nd->update(lf, rg); return; } int mid = (lf + rg) >> 1; if(L <= mid) modify(nd->ls, lf, mid, L, R); if(R > mid) modify(nd->rs, mid+1, rg, L, R); nd->update(lf, rg); } int query(Node *nd, int lf, int rg, int L, int R) { if(nd->cnt) return min(rg,R) - max(lf,L) + 1; if(L <= lf && rg <= R) return nd->sum; int mid = (lf + rg) >> 1; int rt = 0; if(L <= mid) rt += query(nd->ls, lf, mid, L, R); if(R > mid) rt += query(nd->rs, mid+1, rg, L, R); return rt; } struct Event { int x, ymin, ymax, delta; Event(){} Event(int x, int ymin, int ymax, int delta):x(x), ymin(ymin), ymax(ymax), delta(delta){} }; bool operator<(const Event &r, const Event &s) { return r.x < s.x; } int n; int x1 , y1 , x2 , y2 ; vector<Event> events; int main() { for(int i = 1; i <= n; i++) { events.push_back(Event(x1[i], y1[i], y2[i],+1)); events.push_back(Event(x2[i]+1,y1[i], y2[i],-1)); } sort(events.begin(), events.end()); long long ans = 0; for(int t = 0; t < (int)events.size(); t++) { Event &e = events[t]; int dx = (t == 0 ? 0 : events[t].x - events[t-1].x); ans += dx * root->sum; modify(root, 1, n, e.ymin, e.ymax, e.delta); } }
可是还是没有懂离散化扫描线…
以上都是板子,具体题目具体分析。
继续努力!(下周数论我可以go die了
相关文章推荐
- |poj 2763|LCA, 树状数组|或者|树链剖分, 线段树|Housewife Wind
- 单调栈、单调队列、线段树、LCA、二维树状数组、Bitset讲解
- 洛谷[P3616] 富金森林公园【数据结构】【线段树】【树状数组】
- 【算法】逆序对问题的四种解法(归并排序,BST,树状数组,线段树)及变形
- 【HDU5927 2016CCPC东北地区大学生程序设计竞赛 - 重现赛 F】【dfs序 + 线段树 or 树状数组 复杂度计算】Auxiliary Set 一个点如果是好点或是两个好点的LCA就是好
- 上半学期数据结构(线段树,树状数组,二叉搜索树,大(小)堆根堆,树堆)复习
- 单调栈、单调队列、线段树、LCA、二维树状数组、Bitset讲解
- hdu 1166 敌兵布阵(数据结构:树状数组||线段树)
- 树状数组和线段树
- BZOJ3295 动态逆序对 树套树, 树状数组套线段树(主席树)
- [poj3468]树状数组,速度为线段树3倍!!
- poj 2155 二维树状数组 二维线段树
- bzoj 1901: Zju2112 Dynamic Rankings (树状数组套线段树)
- 【原创】【数据结构】一维树状数组的基本操作(单点修改,区间查询) (HDU1166 敌兵布阵)
- nyoj116士兵杀敌(二)【线段树||树状数组】
- HDU 4417 Super Mario(离线线段树or树状数组)
- HDU 1566 Color the ball [树状数组区间更新]【数据结构】
- 树状数组、线段树模板(一)——单点更新 + HDU 1166 敌兵布阵
- 线段树,树状数组基础
- nyoj116 士兵杀敌(二)树状数组与线段树