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

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[N] ;

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[N] ;
long long pre[N];

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 ) ;
    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[N], dest[N], last[N], etot;
int anc[N][P+1], dep[N];

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[N], dest[N], last[N], etot;
int stu[N][P+1];
int pos[N], dep[N], seq[N], idc;
int logb[N];





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[N], anc[N], ch[N], child[N], fat[N] ;//当时多开了一个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[N] ;

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[N];

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[N];

int n;
int aa[N];

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[N], yy[N];
int disc[N], 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[N], y1[N], x2[N], y2[N];
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了

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值