模板集合

Basic

通用模板

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
typedef vector<int> vi;
typedef pair<int,int> pii;

template<typename T>
inline T read(){
    T x=0,f=0;char ch=getchar();
    while(!isdigit(ch)) f|=(ch=='-'),ch=getchar();
    while(isdigit(ch)) x=x*10+(ch^48),ch=getchar();
    return f?-x:x;
}

#define rdi read<int>
#define rdll read<ll>
#define fi first
#define se second
#define pb push_back
#define mp make_pair

int main(){
#ifdef LOCAL
    freopen(".in","r",stdin);
    freopen(".out","w",stdout);
#endif
    return 0;
}

读入优化

namespace GTR {
    const int bufl = 1 << 15;
    char buf[bufl], *s = buf, *t = buf;
    inline int fetch() {
        if (s == t) { t = (s = buf) + fread(buf, 1, bufl, stdin); if (s == t) return EOF; }
        return *s++;
    }
    inline int read() {
        int a = 0, b = 1, c = fetch();
        while (c < 48 || c > 57) b ^= c == '-', c = fetch();
        while (c >= 48 && c <= 57) a = (a << 1) + (a << 3) + c - 48, c = fetch();
        return b ? a : -a;
    }
} using GTR::read;

DS

Segment Tree Beats

区间取 min,区间加,区间求和。

struct Node{
    ll mx,smx,sum;
    int cnt;
    friend Node operator + (Node a,Node b){
        if(!a.cnt) return b;
        if(!b.cnt) return a;
        if(a.mx<b.mx) swap(a,b);
        if(a.mx>b.mx) return {a.mx,max(a.smx,b.mx),a.sum+b.sum,a.cnt};
        else return {a.mx,max(a.smx,b.smx),a.sum+b.sum,a.cnt+b.cnt};
    }
}t[N*4];
ll tmx[N*4],tsum[N*4];
void pushup(int now) {t[now]=t[lson]+t[rson];}
void upd1(int now,ll t1){
    if(t[now].mx<t1) return;
    t[now].sum-=(t[now].mx-t1)*t[now].cnt,t[now].mx=tmx[now]=t1;
}
void upd2(int now,ll t2){
    t[now].mx+=t2,t[now].smx+=t2,t[now].sum+=t[now].cnt1*t2,tsum[now]+=t2,tmx[now]+=t2;
}
void pushdown(int now){
    if(tsum[now]) upd2(lson,tsum[now]),upd2(rson,tsum[now]),tsum[now]=0;
    if(tmx[now]!=INF) upd1(lson,tmx[now]),upd1(rson,tmx[now]),tmx[now]=INF;
}
void add(int now,int l,int r,int x,int y,ll val){
    //与普通线段树相同
    //调用 upd2
}
void chkmin(int now,int l,int r,int x,int y,ll val){
    if(x>y||val>=t[now].mx) return;
    if(x<=l&&r<=y&&val>t[now].smx) return upd1(now,val);
    if(l==r) {t[now].mx=min(t[now].mx,val),t[now].sum=t[now].mx;return;}
    pushdown(now);
    if(x<=mid) chkmin(lson,l,mid,x,y,val);
    if(y>mid) chkmin(rson,mid+1,r,x,y,val);
    pushup(now);
}
void query(){
    //与普通线段树相同
}

李超树

支持插入直线,查询,合并。

struct Line{
    ll k,b;
    ll operator ()(ll x) const{return k*x+b;}
};

struct SGT{
#define lson (t[now].ls)
#define rson (t[now].rs)
#define mid ((l+r)>>1)
    struct Node{Line cur;int ls,rs;}t[N*60];
    int tot;

    int newnode(){
        t[++tot]={{0,INFl},0,0};
        return tot;
    }
    void insert(int &now,int l,int r,Line x){
        if(!now) now=newnode();
        if(t[now].cur(mid)>x(mid)) swap(t[now].cur,x);
        if(l==r) return;
        if(x(l)<t[now].cur(l)) insert(lson,l,mid,x);
        if(x(r)<t[now].cur(r)) insert(rson,mid+1,r,x);
    }
    ll query(int now,int l,int r,int x){
        if(!now) return INFl;
        ll ret=t[now].cur(x);
        if(l==r) return ret;
        ret=min(ret,(x<=mid?query(lson,l,mid,x):query(rson,mid+1,r,x)));
        return ret;
    }
    void merge(int &now1,int now2,int l,int r){
        if(!now1||!now2) {now1|=now2;return;}
        if(l<r){
            merge(t[now1].ls,t[now2].ls,l,mid);
            merge(t[now1].rs,t[now2].rs,mid+1,r);
        }
        insert(now1,l,r,t[now2].cur);
    }
#undef lson
#undef rson
#undef mid
}t;

支持插入线段,区间查询。

struct SGT{
    struct Line{
        i64 k,b;
        i64 operator ()(i64 x) {return x*k+b;}
    };
#define lson (t[now].ls)
#define rson (t[now].rs)
#define mid ((l+r)>>1)
    struct Node{Line p;i64 mi;int ls,rs;}t[N*30];
    int tot,rt;
    SGT(){t[tot=rt=0].mi=INF;}
    int new_n() {t[++tot]={{0,INF},INF,0,0};return tot;}
    void pushup(int now,int l,int r){
        t[now].mi=min({t[lson].mi,t[rson].mi,t[now].p(l),t[now].p(r)});
    }
    void insert(int &now,int l,int r,int x,int y,Line p){
        if(!now) now=new_n();
        if(x<=l&&r<=y){
            if(t[now].p(mid)>p(mid)) swap(t[now].p,p);
            if(l==r) {t[now].mi=t[now].p(l);return;}
            if(p(l)<t[now].p(l)) insert(lson,l,mid,x,y,p);
            if(p(r)<t[now].p(r)) insert(rson,mid+1,r,x,y,p);
            pushup(now,l,r);return;
        }
        if(x<=mid) insert(lson,l,mid,x,y,p);
        if(y>mid) insert(rson,mid+1,r,x,y,p);
        pushup(now,l,r);
    }
    i64 query(int now,int l,int r,int x,int y){
        if(!now) return INF;
        if(x<=l&&r<=y) return t[now].mi;
        i64 ret=min(t[now].p(max(x,l)),t[now].p(min(y,r)));
        if(x<=mid) ret=min(ret,query(lson,l,mid,x,y));
        if(y>mid) ret=min(ret,query(rson,mid+1,r,x,y));
        return ret;
    }
#undef lson
#undef rson
#undef mid
}t;

历史最值线段树

支持区间加减,单点修改(区间赋值以后补)。

struct SGT{
#define lson (now<<1)
#define rson (now<<1|1)
#define mid ((l+r)>>1)
    struct Node{ll mx,hmx,ad,h_ad;}t[N*4];
    void upd(int now,ll ad,ll h_ad){
        t[now].hmx=max(t[now].mx+h_ad,t[now].hmx),t[now].mx+=ad;
        t[now].h_ad=max(t[now].h_ad,t[now].ad+h_ad),t[now].ad+=ad;
    }
    void pushdown(int now){
        if(t[now].ad||t[now].h_ad){
            upd(lson,t[now].ad,t[now].h_ad),upd(rson,t[now].ad,t[now].h_ad);
            t[now].ad=t[now].h_ad=0;
        }
    }
    void pushup(int now){
        t[now].mx=max(t[lson].mx,t[rson].mx);
        t[now].hmx=max({t[now].mx,t[lson].hmx,t[rson].hmx});
    }

    void build(int now,int l,int r){
        t[now].mx=t[now].hmx=-INFl;
        if(l==r) return;
        build(lson,l,mid);build(rson,mid+1,r);
    }
    void add(int now,int l,int r,int x,int y,ll val){
        if(x<=l&&r<=y) {upd(now,val,max(val,0ll));return;}
        pushdown(now);
        if(x<=mid) add(lson,l,mid,x,y,val);
        if(y>mid) add(rson,mid+1,r,x,y,val);
        pushup(now);
    }
    void set(int now,int l,int r,int x,ll val){
        if(l==r){
            t[now].mx=val;
            t[now].hmx=max(t[now].hmx,t[now].mx);
            return;
        }
        pushdown(now);
        x<=mid?set(lson,l,mid,x,val):set(rson,mid+1,r,x,val);
        pushup(now);
    }
    ll query(int now,int l,int r,int x,int y){
        if(x<=l&&r<=y) return t[now].hmx;
        ll ret=-INFl;pushdown(now);
        if(x<=mid) ret=max(ret,query(lson,l,mid,x,y));
        if(y>mid) ret=max(ret,query(rson,mid+1,r,x,y));
        return ret;
    }
#undef lson
#undef rson
#undef mid
};

K-D Tree

单点加,矩形查。


using point=array<int,2>;

template<size_t N>
struct kdtree{
#define lson (t[now].ls)
#define rson (t[now].rs)
    struct Data{point p;i64 val;}buf[N];
    struct Node{
        int ls,rs,siz;i64 sum;
        point mi,mx;Data cur;
    }t[N];
    int fre[N],tp,tot,rt;
    inline int new_n() {return tp?fre[tp--]:++tot;}
    void pushup(int now){
        t[now].siz=t[lson].siz+t[rson].siz+1;
        t[now].sum=t[lson].sum+t[rson].sum+t[now].cur.val;
        t[now].mi=t[now].mx=t[now].cur.p;
        for(int i=0;i<2;i++)
            for(auto son:{lson,rson})
                if(son) t[now].mi[i]=min(t[now].mi[i],t[son].mi[i]),
                        t[now].mx[i]=max(t[now].mx[i],t[son].mx[i]);
    }
    void build(int &now,Data *st,Data *ed,int di){
        if(st==ed) {now=0;return;}
        Data *mid=st+(ed-st)/2;
        nth_element(st,mid,ed,[&](const Data &a,const Data &b){return a.p[di]<b.p[di];});
        t[now=new_n()].cur=*mid,t[now].sum=mid->val;
        build(lson,st,mid,di^1),build(rson,mid+1,ed,di^1);
        pushup(now);
    }
    void print(int now,Data *res){
        if(!now) return;
        print(lson,res);
        fre[++tp]=now,res[t[lson].siz]=t[now].cur;
        print(rson,res+t[lson].siz+1);
    }
    void rebuild(int &now,int di){
        print(now,buf);
        build(now,buf,buf+t[now].siz,di);
    }
    void check(int &now,int di){
        static const db A=0.75;
        db lim=t[now].siz*A;
        if(max(t[lson].siz,t[rson].siz)>lim) rebuild(now,di);
    }
    void insert(int &now,point p,i64 v,int di=0){
        if(!now){
            t[now=new_n()].siz=1;
            t[now].mi=t[now].mx=t[now].cur.p=p;
            t[now].sum=t[now].cur.val=v;
            return;
        }
        if(p[di]<=t[now].cur.p[di]) insert(lson,p,v,di^1);
        else insert(rson,p,v,di^1);
        pushup(now);check(now,di);
    }
    i64 query(int now,point p1,point p2,int di=0){
        if(!now||t[now].mx[0]<p1[0]||p2[0]<t[now].mi[0]||
            t[now].mx[1]<p1[1]||p2[1]<t[now].mi[1]) return 0;
        if(p1[0]<=t[now].mi[0]&&t[now].mx[0]<=p2[0]&&
            p1[1]<=t[now].mi[1]&&t[now].mx[1]<=p2[1]) return t[now].sum;
        i64 ret=0;
        if(p1[0]<=t[now].cur.p[0]&&t[now].cur.p[0]<=p2[0]&&
            p1[1]<=t[now].cur.p[1]&&t[now].cur.p[1]<=p2[1]) ret+=t[now].cur.val;
        ret+=query(lson,p1,p2,di^1)+query(rson,p1,p2,di^1);
        return ret;
    }
#undef lson
#undef rson
};

Geometry

向量类

struct Vec{
    double x,y;
    friend bool operator == (Vec a,Vec b){return a.x==b.x&&a.y==b.y;}
    double abs() const{return hypot(x,y);}
    double deg() const{return atan2(y,x);}
};

Vec operator + (const Vec &a,const Vec &b) {return {a.x+b.x,a.y+b.y};}
Vec operator - (const Vec &a,const Vec &b) {return {a.x-b.x,a.y-b.y};}
double dot(const Vec &a,const Vec &b) {return a.x*b.x+a.y*b.y;}
double cross(const Vec &a,const Vec &b) {return a.x*b.y-a.y*b.x;}

凸包

vector<Vec> convex(vector<Vec> v){
    int cnt=v.size();
    for(int i=1;i<cnt;i++)
        if(v[i].y<v[0].y||(v[i].y==v[0].y&&v[i].x<v[0].x)) swap(v[i],v[0]);
    sort(v.begin()+1,v.end(),[&](Vec a,Vec b){
        double val=cross(a-v[0],b-v[0]);
        return fabs(val)<eps?mp(a.x,a.y)<mp(b.x,b.y):val>0;
    });
    static int st[N],tp;
    st[tp=1]=0;
    for(int i=1;i<cnt;i++){
        while(tp>1&&cross(v[i]-v[st[tp-1]],v[st[tp]]-v[st[tp-1]])>=0) --tp;
        st[++tp]=i;
    }
    vector<Vec> ret(tp);
    for(int i=0;i<tp;i++) ret[i]=v[st[i+1]];
    return ret;
}

多边形面积

double area(const vector<Vec> &a){
    int siz=a.size();
    double sum=0;
    for(int i=0;i<siz;i++){
        int nxt=(i+1>=siz?i+1-siz:i+1);
        sum+=cross(a[i],a[nxt]);
    }
    return abs(sum/2);
}

Graph

欧拉路/回路

只有定向,没有输出路径。

struct Edge{int to,nxt,fx;}e[N];
int head[N],tot=1,vis[N];
void add_e(int x,int y){
    e[++tot]={y,head[x],0};
    head[x]=tot;
}
void euler(int x){
    for(int &i=head[x];i;i=e[i].nxt){
        if(vis[i>>1]) continue;
        vis[i>>1]=1,e[i].fx=1;
        euler(e[i].to);
    }
}

String

Suffix Array

来自 OI-wiki。

#include <algorithm>
#include <cstdio>
#include <cstring>
#include <iostream>

using namespace std;

const int N = 1000010;

char s[N];
int n, sa[N], rk[N], oldrk[N << 1], id[N], px[N], cnt[N];

// px[i] = rk[id[i]](用于排序的数组所以叫 px)

bool cmp(int x, int y, int w) {
    return oldrk[x] == oldrk[y] && oldrk[x + w] == oldrk[y + w];
}

int main() {
    int i, m = 300, p, w;

    scanf("%s", s + 1);
    n = strlen(s + 1);
    for (i = 1; i <= n; ++i)
        ++cnt[rk[i] = s[i]];
    for (i = 1; i <= m; ++i)
        cnt[i] += cnt[i - 1];
    for (i = n; i >= 1; --i)
        sa[cnt[rk[i]]--] = i;

    for (w = 1;; w <<= 1, m = p) { // m=p 就是优化计数排序值域
        for (p = 0, i = n; i > n - w; --i)
            id[++p] = i;
        for (i = 1; i <= n; ++i)
            if (sa[i] > w)
                id[++p] = sa[i] - w;
        memset(cnt, 0, sizeof(cnt));
        for (i = 1; i <= n; ++i)
            ++cnt[px[i] = rk[id[i]]];
        for (i = 1; i <= m; ++i)
            cnt[i] += cnt[i - 1];
        for (i = n; i >= 1; --i)
            sa[cnt[px[i]]--] = id[i];
        memcpy(oldrk, rk, sizeof(rk));
        for (p = 0, i = 1; i <= n; ++i)
            rk[sa[i]] = cmp(sa[i], sa[i - 1], w) ? p : ++p;
        if (p == n) {
            for (int i = 1; i <= n; ++i)
                sa[rk[i]] = i;
            break;
        }
    }

    for (i = 1; i <= n; ++i)
        printf("%d ", sa[i]);

    return 0;
}

\(\mathit{height}\) 数组

来自 OI-wiki。

for (i = 1, k = 0; i <= n; ++i) {
    if (rk[i] == 1) continue;
    if (k) --k;
    while (s[i + k] == s[sa[rk[i] - 1] + k]) ++k;
    height[rk[i]] = k;
}
posted @ 2022-02-14 14:25  Zesty_Fox  阅读(93)  评论(0编辑  收藏  举报