zoukankan      html  css  js  c++  java
  • 3 、 结构

    3.1 并查集

    //带路径压缩的并查集,用于动态维护查询等价类
    //图论算法中动态判点集连通常用
    //维护和查询复杂度略大于 O(1)
    //集合元素取值 1..MAXN-1(注意 0 不能用!),默认不等价
    #include <string.h>
    #define MAXN 100000
    #define _ufind_run(x) for(;p[t=x];x=p[x],p[t]=(p[x]?p[x]:x))
    #define _run_both _ufind_run(i);_ufind_run(j)
    struct ufind{
    int p[MAXN],t;
    void init(){memset(p,0,sizeof(p));}
    void set_friend(int i,int j){_run_both;p[i]=(i==j?0:j);}
    int is_friend(int i,int j){_run_both;return i==j&&i;}
    };
    //带路径压缩的并查集扩展形式
    //用于动态维护查询 friend-enemy 型等价类
    //维护和查询复杂度略大于 O(1)
    //集合元素取值 1..MAXN-1(注意 0 不能用!),默认无关
    #include <string.h>
    #define MAXN 100000
    #define sig(x) ((x)>0?1:-1)
    59
    #define abs(x) ((x)>0?(x):-(x))
    #define _ufind_run(x)
    for(;p[t=abs(x)];x=sig(x)*p[abs(x)],p[t]=sig(p[t])*(p[abs(x)]?p[abs(x)]:abs(p[t])))
    #define _run_both _ufind_run(i);_ufind_run(j)
    #define _set_side(x) p[abs(i)]=sig(i)*(abs(i)==abs(j)?0:(x)*j)
    #define _judge_side(x) (i==(x)*j&&i)
    struct ufind{
    int p[MAXN],t;
    void init(){memset(p,0,sizeof(p));}
    int set_friend(int i,int j){_run_both;_set_side(1);return !_judge_side(-1);}
    int set_enemy(int i,int j){_run_both;_set_side(-1);return !_judge_side(1);}
    int is_friend(int i,int j){_run_both;return _judge_side(1);}
    int is_enemy(int i,int j){_run_both;return _judge_side(-1);}
    };

    3.2 堆

    //二分堆(binary)
    //可插入,获取并删除最小(最大)元素,复杂度均 O(logn)
    //可更改元素类型,修改比较符号或换成比较函数
    #define MAXN 10000
    #define _cp(a,b) ((a)<(b))
    typedef int elem_t;
    struct heap{
    elem_t h[MAXN];
    int n,p,c;
    void init(){n=0;}
    void ins(elem_t e){
    for (p=++n;p>1&&_cp(e,h[p>>1]);h[p]=h[p>>1],p>>=1);
    h[p]=e;
    }
    int del(elem_t& e){
    if (!n) return 0;
    for
    (e=h[p=1],c=2;c<n&&_cp(h[c+=(c<n-1&&_cp(h[c+1],h[c]))],h[n]);h[p]=h[c],p=c,c<<=1);
    h[p]=h[n--];return 1;
    }
    };
    //映射二分堆(mapped)
    //可插入,获取并删除任意元素,复杂度均 O(logn)
    //插入时提供一个索引值,删除时按该索引删除,获取并删除最小元素时一起获得该索引
    //索引值范围 0..MAXN-1,不能重复,不负责维护索引的唯一性,不在此返回请另外映射
    //主要用于图论算法,该索引值可以是节点的下标
    //可更改元素类型,修改比较符号或换成比较函数
    #define MAXN 10000
    #define _cp(a,b) ((a)<(b))
    typedef int elem_t;
    struct heap{
    elem_t h[MAXN];
    int ind[MAXN],map[MAXN],n,p,c;
    void init(){n=0;}
    void ins(int i,elem_t e){
    for (p=++n;p>1&&_cp(e,h[p>>1]);h[map[ind[p]=ind[p>>1]]=p]=h[p>>1],p>>=1);
    h[map[ind[p]=i]=p]=e;
    }
    int del(int i,elem_t& e){
    i=map[i];if (i<1||i>n) return 0;
    for (e=h[p=i];p>1;h[map[ind[p]=ind[p>>1]]=p]=h[p>>1],p>>=1);
    for
    (c=2;c<n&&_cp(h[c+=(c<n-1&&_cp(h[c+1],h[c]))],h[n]);h[map[ind[p]=ind[c]]=p]=h[c],p=c,c<<
    =1);
    h[map[ind[p]=ind[n]]=p]=h[n];n--;return 1;
    }
    int delmin(int& i,elem_t& e){
    if (n<1) return 0;i=ind[1];
    for
    (e=h[p=1],c=2;c<n&&_cp(h[c+=(c<n-1&&_cp(h[c+1],h[c]))],h[n]);h[map[ind[p]=ind[c]]=p]=h[c
    ],p=c,c<<=1);
    h[map[ind[p]=ind[n]]=p]=h[n];n--;return 1;
    }
    };

    3.3 线段树

    线段树应用:
    求面积:
    1) 坐标离散化
    2) 垂直边按 x 坐标排序
    3) 从左往右用线段树处理垂直边
    累计每个离散 x 区间长度和线段树长度的乘积
    求周长:
    1) 坐标离散化
    2) 垂直边按 x 坐标排序, 第二关键字为入边优于出边
    3) 从左往右用线段树处理垂直边
    61
    在每个离散点上先加入所有入边, 累计线段树长度变化值
    再删除所有出边, 累计线段树长度变化值
    4) 水平边按 y 坐标排序, 第二关键字为入边优于出边
    5) 从上往下用线段树处理水平边
    在每个离散点上先加入所有入边, 累计线段树长度变化值
    再删除所有出边, 累计线段树长度变化值

    //线段树
    //可以处理加入边和删除边不同的情况
    //inc_seg 和 dec_seg 用于加入边
    //seg_len 求长度
    //t 传根节点(一律为 1)
    //l0,r0 传树的节点范围(一律为 1..t)
    //l,r 传线段(端点)
    #define MAXN 10000
    struct segtree{
    int n,cnt[MAXN],len[MAXN];
    segtree(int t):n(t){
    for (int i=1;i<=t;i++)
    cnt[i]=len[i]=0;
    };
    void update(int t,int l,int r);
    void inc_seg(int t,int l0,int r0,int l,int r);
    void dec_seg(int t,int l0,int r0,int l,int r);
    int seg_len(int t,int l0,int r0,int l,int r);
    };
    int length(int l,int r){
    return r-l;
    }
    void segtree::update(int t,int l,int r){
    if (cnt[t]||r-l==1)
    len[t]=length(l,r);
    else
    len[t]=len[t+t]+len[t+t+1];
    }
    void segtree::inc_seg(int t,int l0,int r0,int l,int r){
    if (l0==l&&r0==r)
    cnt[t]++;
    else{
    int m0=(l0+r0)>>1;
    if (l<m0)
    inc_seg(t+t,l0,m0,l,m0<r?m0:r);
    if (r>m0)
    inc_seg(t+t+1,m0,r0,m0>l?m0:l,r);
    if (cnt[t+t]&&cnt[t+t+1]){
    cnt[t+t]--;
    update(t+t,l0,m0);
    cnt[t+t+1]--;
    update(t+t+1,m0,r0);
    cnt[t]++;
    }
    }
    update(t,l0,r0);
    }
    void segtree::dec_seg(int t,int l0,int r0,int l,int r){
    if (l0==l&&r0==r)
    cnt[t]--;
    else if (cnt[t]){
    cnt[t]--;
    if (l>l0)
    inc_seg(t,l0,r0,l0,l);
    if (r<r0)
    inc_seg(t,l0,r0,r,r0);
    }
    else{
    int m0=(l0+r0)>>1;
    if (l<m0)
    dec_seg(t+t,l0,m0,l,m0<r?m0:r);
    if (r>m0)
    dec_seg(t+t+1,m0,r0,m0>l?m0:l,r);
    }
    update(t,l0,r0);
    }
    int segtree::seg_len(int t,int l0,int r0,int l,int r){
    if (cnt[t]||(l0==l&&r0==r))
    return len[t];
    else{
    int m0=(l0+r0)>>1,ret=0;
    if (l<m0)
    ret+=seg_len(t+t,l0,m0,l,m0<r?m0:r);
    if (r>m0)
    ret+=seg_len(t+t+1,m0,r0,m0>l?m0:l,r);
    return ret;
    }
    }
    //线段树扩展
    //可以计算长度和线段数
    //可以处理加入边和删除边不同的情况
    //inc_seg 和 dec_seg 用于加入边
    //seg_len 求长度,seg_cut 求线段数
    //t 传根节点(一律为 1)
    //l0,r0 传树的节点范围(一律为 1..t)
    //l,r 传线段(端点)
    #define MAXN 10000
    struct segtree{
    int n,cnt[MAXN],len[MAXN],cut[MAXN],bl[MAXN],br[MAXN];
    segtree(int t):n(t){
    for (int i=1;i<=t;i++)
    cnt[i]=len[i]=cut[i]=bl[i]=br[i]=0;
    };
    void update(int t,int l,int r);
    void inc_seg(int t,int l0,int r0,int l,int r);
    void dec_seg(int t,int l0,int r0,int l,int r);
    int seg_len(int t,int l0,int r0,int l,int r);
    int seg_cut(int t,int l0,int r0,int l,int r);
    };
    int length(int l,int r){
    return r-l;
    }
    void segtree::update(int t,int l,int r){
    if (cnt[t]||r-l==1)
    len[t]=length(l,r),cut[t]=bl[t]=br[t]=1;
    else{
    len[t]=len[t+t]+len[t+t+1];
    cut[t]=cut[t+t]+cut[t+t+1];
    if (br[t+t]&&bl[t+t+1])
    cut[t]--;
    bl[t]=bl[t+t],br[t]=br[t+t+1];
    }
    }
    void segtree::inc_seg(int t,int l0,int r0,int l,int r){
    if (l0==l&&r0==r)
    cnt[t]++;
    64
    else{
    int m0=(l0+r0)>>1;
    if (l<m0)
    inc_seg(t+t,l0,m0,l,m0<r?m0:r);
    if (r>m0)
    inc_seg(t+t+1,m0,r0,m0>l?m0:l,r);
    if (cnt[t+t]&&cnt[t+t+1]){
    cnt[t+t]--;
    update(t+t,l0,m0);
    cnt[t+t+1]--;
    update(t+t+1,m0,r0);
    cnt[t]++;
    }
    }
    update(t,l0,r0);
    }
    void segtree::dec_seg(int t,int l0,int r0,int l,int r){
    if (l0==l&&r0==r)
    cnt[t]--;
    else if (cnt[t]){
    cnt[t]--;
    if (l>l0)
    inc_seg(t,l0,r0,l0,l);
    if (r<r0)
    inc_seg(t,l0,r0,r,r0);
    }
    else{
    int m0=(l0+r0)>>1;
    if (l<m0)
    dec_seg(t+t,l0,m0,l,m0<r?m0:r);
    if (r>m0)
    dec_seg(t+t+1,m0,r0,m0>l?m0:l,r);
    }
    update(t,l0,r0);
    }
    int segtree::seg_len(int t,int l0,int r0,int l,int r){
    if (cnt[t]||(l0==l&&r0==r))
    return len[t];
    else{
    int m0=(l0+r0)>>1,ret=0;
    if (l<m0)
    ret+=seg_len(t+t,l0,m0,l,m0<r?m0:r);
    65
    if (r>m0)
    ret+=seg_len(t+t+1,m0,r0,m0>l?m0:l,r);
    return ret;
    }
    }
    int segtree::seg_cut(int t,int l0,int r0,int l,int r){
    if (cnt[t])
    return 1;
    if (l0==l&&r0==r)
    return cut[t];
    else{
    int m0=(l0+r0)>>1,ret=0;
    if (l<m0)
    ret+=seg_cut(t+t,l0,m0,l,m0<r?m0:r);
    if (r>m0)
    ret+=seg_cut(t+t+1,m0,r0,m0>l?m0:l,r);
    if (l<m0&&r>m0&&br[t+t]&&bl[t+t+1])
    ret--;
    return ret;
    }
    }

    3.4 子段和

    //求 sum{[0..n-1]}
    //维护和查询复杂度均为 O(logn)
    //用于动态求子段和,数组内容保存在 sum.a[]中
    //可以改成其他数据类型
    #include <string.h>
    #define lowbit(x) ((x)&((x)^((x)-1)))
    #define MAXN 10000
    typedef int elem_t;
    struct sum{
    elem_t a[MAXN],c[MAXN],ret;
    int n;
    void init(int i){memset(a,0,sizeof(a));memset(c,0,sizeof(c));n=i;}
    void update(int i,elem_t v){for (v-=a[i],a[i++]+=v;i<=n;c[i-1]+=v,i+=lowbit(i));}
    elem_t query(int i){for (ret=0;i;ret+=c[i-1],i^=lowbit(i));return ret;}
    };

    3.5 子阵和

    //求 sum{a[0..m-1][0..n-1]}
    //维护和查询复杂度均为 O(logm*logn)
    //用于动态求子阵和,数组内容保存在 sum.a[][]中
    //可以改成其他数据类型
    #include <string.h>
    #define lowbit(x) ((x)&((x)^((x)-1)))
    #define MAXN 100
    typedef int elem_t;
    struct sum{
    elem_t a[MAXN][MAXN],c[MAXN][MAXN],ret;
    int m,n,t;
    void init(int i,int j){memset(a,0,sizeof(a));memset(c,0,sizeof(c));m=i,n=j;}
    void update(int i,int j,elem_t v){
    for (v-=a[i][j],a[i++][j++]+=v,t=j;i<=m;i+=lowbit(i))
    for (j=t;j<=n;c[i-1][j-1]+=v,j+=lowbit(j));
    }
    elem_t query(int i,int j){
    for (ret=0,t=j;i;i^=lowbit(i))
    for (j=t;j;ret+=c[i-1][j-1],j^=lowbit(j));
    return ret;
    }
    };
  • 相关阅读:
    day47---分组多表查询练习
    day47---数据库进阶知识(二)
    day46---数据库练习
    安全项目(癞蛤蟆病毒)
    pywin32安装步骤
    pip安装报错:error:Microsoft Visual C++ 14.0
    windows下anaconda安装
    数据库常用命令
    MySQL数据库初识
    linux安装MySQL
  • 原文地址:https://www.cnblogs.com/godoforange/p/11240482.html
Copyright © 2011-2022 走看看