您的位置:首页 > 理论基础 > 数据结构算法

数据结构:线段树(树状数组、BST、LCA、

2018-02-09 17:22 525 查看
2018.2.5 - 2018.2.9

跟着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了
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐