各种模板总结

  • 数据结构
    • 线段树
    • 树链剖分 √
    • Treap
    • Splay
    • 左偏堆
    • 划分树 待添加
  • 字符串
    • KMP
    • MANACHER
    • 字典树
    • 01字典树 √
    • AC自动机 √
    • 后缀数组 √
    • 回文树 √
  • 数论
    • 矩阵快速幂 待添加
  • 图论
    • 最短路(Dijkastra)待添加
    • 最短路(Floyd)待添加
    • 最短路(SPFA)待添加
    • 最小生成树(Prim) 待添加
    • 最小生成树(Kurskal) 待添加
  • 计算几何
    • 扫描线 √
  • 其他
    • 大整数模板 √
    • 快速输入模板 (整数) √
    • 快速输入模板 (实数) √
    • 1~MOD的逆元 √
  • -

树链剖分

const int maxn = 100000 + 5;        //树中节点个数


//边集
struct Edge{
    int v,pre,c;
}Es[maxn * 2];
int head[maxn],TOT_EDGE;
void INIT_EDGE(){                   //边集初始化
    memset(head,-1,sizeof head);
    TOT_EDGE = 0;
}
void ADD_EDGE(int u,int v,int c){   //添加边
    Es[TOT_EDGE].v = v;
    Es[TOT_EDGE].c = c;
    Es[TOT_EDGE].pre = head[u];
    head[u] = TOT_EDGE++;
}

/**树链剖分部分*/
/**
**  son:    节点重儿子
**  fa:     节点父节点
**  dep:    节点在树中深度
**  size:   节点子树的大小
**  top:    节点在重链中的深度最低节点(最高节点)
**  tid:    节点编号(hash值)
**  RANK:   RANK[v]编号为v的是第RANK[v]节点
**  SegSize:用于编号的迭代辅助变量,最小编号为SegSize的初始值
*/
int son[maxn],fa[maxn],dep[maxn],size[maxn];
int top[maxn],tid[maxn],RANK[maxn],SegSize;
int DFS(int rt){
    dep[rt] = dep[fa[rt]] + 1;
    son[rt] = 0;
    size[rt] = 1;
    for(int i = head[rt];~i;i = Es[i].pre){
        int v = Es[i].v;
        if(v != fa[rt]){
            fa[v] = rt;
            size[rt] += DFS(v);
            if(size[son[rt]] < size[v]) son[rt] = v;
        }
    }
    return size[rt];
}
void Split(int rt,int tp){
    top[rt] = tp;
    tid[rt] = ++SegSize;
    RANK[tid[rt]] = rt;
    if(son[rt]){
        Split(son[rt],tp);
        for(int i = head[rt];~i;i = Es[i].pre){
            int v = Es[i].v;
            if(v != fa[rt] && v != son[rt]) Split(v,v);
        }
    }
}
void TreeLineSplit(){       //开始剖分
    dep[0] = 0;
    size[0] = 0;
    fa[1] = 0;
    DFS(1);
    SegSize = -1;
    Split(1,1);
}

Treap

/**
**  ch:节点的孩子节点
**  fa:夫节点
**  fix;优先级
**  size:当前子树的大小
**  tot:节点个数(包括sroot)
**  sroot:超级根节点
**  key:节点的键值
*/
const int maxn = 15000 + 50,INF = 0x7fffffff;
int ch[maxn][2],fa[maxn],fix[maxn],size[maxn];
int tot,root,sroot;
int key[maxn];


/**
**  Treap初始化
*/
void Treap_Init(){
    tot = 1;
    root = sroot = 0;
    ch[sroot][0] = ch[sroot][1] = 0;
    fa[sroot] = 0;
    size[sroot] = 0;
    fix[sroot] = key[sroot] = INF;
}

/**
**  新建一个父节点为FA,键值为k的节点,返回节点编号
**
*/
int NewNode(int FA,int k){
    ch[tot][0] = ch[tot][1] = 0;
    fa[tot] = FA;
    size[tot] = 1;
    fix[tot] = rand();
    key[tot] = k;
    return tot++;
}

/**
**  更新rt的size信息
*/
void PushUp(int rt){ size[rt] = size[ch[rt][0]] + size[ch[rt][1]] + 1; if(rt == sroot) size[rt] = 0;}

/**
**  旋转操作
**  kind:   0.表示rt为fa[rt]的左孩子 进行右旋操作 zig
**  kind:   1.表示rt为fa[rt]的右孩子 进行左旋操作 zag
*/
void rotate(int rt,int kind){
    int prt = fa[rt];
    ch[prt][kind] = ch[rt][!kind];fa[ch[rt][!kind]] = prt;
    ch[fa[prt]][ch[fa[prt]][1] == prt] = rt;fa[rt] = fa[prt];
    ch[rt][!kind] = prt;fa[prt] = rt;
    PushUp(prt);PushUp(rt);
}

/**
**  在根为rt的树中插入键值为K的元素 这里可以重复键值
*/
void Insert(int rt,int k){
    while(ch[rt][k >= key[rt]]) rt = ch[rt][k >= key[rt]];
    ch[rt][k >= key[rt]] = NewNode(rt,k);
    rt = ch[rt][k >= key[rt]];
    while(fa[rt] != sroot && fix[rt] > fix[fa[rt]]) rotate(rt,ch[fa[rt]][1] == rt);
    if(fa[rt] == sroot) root = rt;
    while(fa[rt] != sroot){
        rt = fa[rt];PushUp(rt);
    }
}

/**
**  删除键值为k的节点,使用前要保证一定有键值为k的节点
*/
void Delete(int rt,int k){
    if(key[rt] == k){
        if(ch[rt][0] && ch[rt][1]){
            int nrt = ch[rt][0];
            if(fix[nrt] < fix[ch[rt][1]]) nrt = ch[rt][1];
            rotate(nrt,ch[rt][1] == nrt);
            Delete(rt,k);PushUp(nrt);
        }
        else{
            int nrt = ch[rt][0];
            if(nrt == sroot) nrt = ch[rt][1];
            ch[fa[rt]][ch[fa[rt]][1] == rt] = nrt;fa[nrt] = fa[rt];
        }
    }
    else{
        Delete(ch[rt][k >= key[rt]],k);
        PushUp(rt);
    }
}

/**
**  在rt的树中查找键值第k小的节点 返回节点编号
*/
int Search(int rt,int k){
    if(k <= size[ch[rt][0]]) return Search(ch[rt][0],k);
    else if(k > size[ch[rt][0]] + 1) return Search(ch[rt][1],k - 1 - size[ch[rt][0]]);
    else return rt;
}

/**
**  查找键值为k的节点在树中是第几小的
*/
int getRank(int rt,int k){
    if(rt == sroot) return 0;
    if(k >= key[rt]) return size[ch[rt][0]] + 1 + getRank(ch[rt][1],k);
    else return getRank(ch[rt][0],k);
}

Splay

/** ---- SPLAY ---- **/
/**  ch     边
 **  fa     父节点
 **  size   子树大小
 **  key    关键字大小
 **  tot    总共节点的个数
 **  root   当前的树根
 **  sroot  超级根节点
**/
int ch[maxn][2],fa[maxn],size[maxn];
int key[maxn],pos[maxn];
int tot,root,sroot;

/** 初始化 */
void Splay_Init(){
    tot = 1;
    root = sroot = 0;
    ch[0][0] = ch[0][1] = 0;
    fa[0] = 0;
    key[0] = INF;
    size[0] = 0;
}

/** 新建一个节点 */
int NewNode(int FA,int k,int p){
    ch[tot][0] = ch[tot][1] = 0;
    fa[tot] = FA;
    size[tot] = 1;
    key[tot] = k,pos[tot] = p;
    return tot++;
}

/** 更新当前子树的大小 和 根节点保留的信息 */
void PushUp(int rt){size[rt] = 1 + size[ch[rt][0]] + size[ch[rt][1]];}


/** 节点的旋转操作
**  kind 0 表示rt为fa[rt]的左孩子
**  kind 1 表示rt为fa[rt]的右孩子
**  kind 0 进行zig 1 进行zag
*/
void rotate(int rt,int kind){
    int prt = fa[rt];
    ch[prt][kind] = ch[rt][!kind];fa[ch[rt][!kind]] = prt;
    ch[fa[prt]][ch[fa[prt]][1] == prt] = rt;fa[rt] = fa[prt];
    ch[rt][!kind] = prt;fa[prt] = rt;
    PushUp(prt);PushUp(rt);
}

/** 将rt节点 伸展至goal的孩子节点 */
void Splay(int rt,int goal){
    while(fa[rt] != goal){
        if(fa[fa[rt]] == goal) rotate(rt,ch[fa[rt]][1] == rt);
        else{
            int prt = fa[rt],kind = (ch[fa[prt]][1] == prt);
            if(ch[prt][kind] == rt) rotate(rt,kind),rotate(rt,kind);
            else rotate(rt,!kind),rotate(rt,kind);
        }
    }
    if(fa[rt] == sroot) root = rt;
}

/** 在根为rt的树内,插入关键字为k的节点 */
void Insert(int rt,int k,int p){
    while(ch[rt][k > key[rt]]) rt = ch[rt][k > key[rt]];
    rt = (ch[rt][k > key[rt]] = NewNode(rt,k,p));
    Splay(rt,sroot);
}

/** 在根为rt的树内,查找关键字为k的节点 */
int Find(int rt,int k){
    while(ch[rt][k >= key[rt]])
        if(k == key[rt]) return rt;
        else rt = ch[rt][k >= key[rt]];
    return sroot;
}

/** 查找关键字为k 的前驱 */
int Find_Pre(int rt,int k){
    rt = Find(rt,k);
    Splay(rt,sroot);
    if(ch[rt][0] == sroot) return sroot;
    else rt = ch[rt][0];
    while(ch[rt][1]) rt = ch[rt][1];
    return rt;
}

/** 查找关键字为k 的后继 */
int Find_Next(int rt,int k){
    rt = Find(rt,k);
    Splay(rt,sroot);
    if(ch[rt][1] == sroot) return sroot;
    else rt = ch[rt][1];
    while(ch[rt][0]) rt = ch[rt][0];
    return rt;
}

01字典树

const int maxn = 100000 + 5;        //集合中的数字个数
typedef long long LL;
int ch[32 * maxn][2];               //节点的边信息
LL value[32 * maxn];                //节点存储的值
int node_cnt;                       //树中当前节点个数

inline void init(){                 //树清空
    node_cnt = 1;
    memset(ch[0],0,sizeof(ch));
}           

inline void Insert(LL x){           //在字典树中插入 X    
                                    //和一般字典树的操作相同 将X的二进制插入到字典树中
    int cur = 0;
    for(int i = 32;i >= 0;--i){
        int idx = (x >> i) & 1;
        if(!ch[cur][idx]){
            memset(ch[node_cnt],0,sizeof(ch[node_cnt]));
            ch[cur][idx] = node_cnt;
            value[node_cnt++] = 0;
        }
            cur = ch[cur][idx];
        }
        value[cur] = x;             //最后的节点插入value
}

inline LL Query(LL x){              //在字典树中查找和X异或的最大值的元素Y 返回Y的值
    int cur = 0;
    for(int i = 32;i >= 0;--i){
        int idx = (x >> i) & 1;
        if(ch[cur][idx ^ 1]) cur = ch[cur][idx ^ 1];
        else cur = ch[cur][idx];
    }
    return value[cur];
}

KMP

const int maxn = 100;
char s[maxn],p[maxn];
int fail[maxn];
/*  p为模式串
**  f为保存失配边的数组
**
*/
void getFail(char* p,int* f){
    int m = strlen(p);
    f[0] = 0; f[1] = 0;
    for(int i = 1;i < m;++i){
        int j = f[i];
        while(j && p[i] != p[j]) j = f[j];
        f[i + 1] = p[i] == p[j] ? j + 1 : 0;
    }
}
/*
**  s为文本串 p为模式串,fail保存失配边
**  匹配成功返回true
**  失败返回false
*/
bool Match(char* s,char* p,int* fail){
    getFail(p,fail);//得到fail数值
    int m = strlen(p),n = strlen(s);
    int i = 0, j = 0;
    while(i < n){
        while(i < n && j < m && s[i] == s[j]){//新一轮匹配
            i++,j++;
        }
        if(j == m) return true;//匹配成功
        j--;
        while(j && p[j] != s[i]) j = fail[j];//根据fail跳转
    }
    return false;
}

AC自动机

const int maxn = 10000 * 50 + 50,sigma_size = 26;

/** AC_AUTOMATON */
int ch[maxn][sigma_size],fail[maxn],tot;
int value[maxn];

/** 初始化 */
void Init(){
    memset(ch[0],0,sizeof ch[0]);
    tot = 1;
    fail[0] = -1;value[0] = 0;
}

/** 插入字符串 s */
void Insert(char* s){
    int idx,cur = 0;
    while( *s ){
        idx = *s - 'a';
        if(ch[cur][idx] == 0){
            memset(ch[tot],0,sizeof ch[tot]);
            fail[tot] = 0;
            value[tot] = 0;
            ch[cur][idx] = tot++;
        }
        cur = ch[cur][idx];
        s++;
    }
    value[cur]++;
}

/** GetFail */
void GetFail(){
    queue<int> Q;
    Q.push(0);
    fail[0] = -1;
    int cur,idx,f;
    while(!Q.empty()){
        cur = Q.front();Q.pop();
        for(int i = 0;i < sigma_size;++i){
            if(ch[cur][i]){
                f = fail[cur];
                while(f != -1 && ch[f][i] == 0) f = fail[f];
                fail[ch[cur][i]] = (f == -1) ? 0 : ch[f][i];
                Q.push(ch[cur][i]);
            }
            else{
                f = fail[cur];
                ch[cur][i] = (f == -1) ? 0 : ch[f][i];
            }
        }
    }
}
/**  以上具有通用性 */
/** 匹配 */
int Search(char *s){
    int cur = 0,idx,ret = 0,tmp;
    while(*s){
        idx = *s - 'a';
        tmp = cur = ch[cur][idx];
        if(value[tmp]) while(tmp){
            ret += value[tmp];value[tmp] = 0;
            tmp = fail[tmp];
        }
        s++;
    }
    return ret;
}

MANACHER

const int maxn = 500;
int dis[maxn];
char str1[maxn],str2[maxn];

int get_dis(){
    int len = strlen(str1);
    str2[0] = '$';
    char* str_a = str2 + 1;
    for(int i = 0;i <= len;++i){
        str_a[i * 2] = '#';
        str_a[i * 2 + 1] = str1[i];
    }
    int id = 0, mx = 1,len2 = strlen(str2);
    for(int i = 1;i < len2;++i){
        if(mx > i){
            dis[i] = (dis[id * 2 - i] < (mx - i) ? dis[2 * id - i] : (mx - i));
        }
        else dis[i] = 1;
        while(str2[i - dis[i]] == str2[i + dis[i]]) dis[i]++;
        if(i + dis[i] > mx){
        mx = i + dis[i];
            id = i;
        }
    }
    return len2;
}

后缀数组

int wa[maxn],wb[maxn],wv[maxn],ws[maxn];
int cmp(int *r,int a,int b,int l)
{return r[a]==r[b]&&r[a+l]==r[b+l];}
void da(int *r,int *sa,int n,int m)
{
    int i,j,p,*x=wa,*y=wb,*t;

    for(i=0;i<m;i++) ws[i]=0;
    for(i=0;i<n;i++) ws[x[i]=r[i]]++;
    for(i=1;i<m;i++) ws[i]+=ws[i-1];
    for(i=n-1;i>=0;i--) sa[--ws[x[i]]]=i;
    for(j=1,p=1;p<n;j*=2,m=p)
    {

        for(p=0,i=n-j;i<n;i++) y[p++]=i;
        for(i=0;i<n;i++) if(sa[i]>=j) y[p++]=sa[i]-j;

        for(i=0;i<n;i++) wv[i]=x[y[i]];

        for(i=0;i<m;i++) ws[i]=0;
        for(i=0;i<n;i++) ws[wv[i]]++;
        for(i=1;i<m;i++) ws[i]+=ws[i-1];
        for(i=n-1;i>=0;i--) sa[--ws[wv[i]]]=y[i];
        for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1;i<n;i++)
        x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
    }
    return;
}
int rank[maxn],height[maxn];
void calheight(int *r,int *sa,int n)
{
    int i,j,k=0;
    for(i=1;i<=n;i++) rank[sa[i]]=i;
    for(i=0;i<n;height[rank[i++]]=k)
    for(k?k--:0,j=sa[rank[i]-1];r[i+k]==r[j+k];k++);
    return;
}

回文树

const int MAXN = 100005;

struct node {
    int next[26];   //边
    int len;        //回文串长度
    int sufflink;   //后缀指针
    int num;
};

int len;
char s[MAXN];
node tree[MAXN];
int num;            // node 1 - root with len -1, node 2 - root with len 0
int suff;           // max suffix palindrome
long long ans;

bool addLetter(int pos) {

    int cur = suff, curlen = 0;
    int let = s[pos] - 'a';

    while (true) {
        curlen = tree[cur].len;                                     //当前可能上一个回文串长度
        if (pos - 1 - curlen >= 0 && s[pos - 1 - curlen] == s[pos]) //如果能形成行如XAX的回文串
            break;
        cur = tree[cur].sufflink;                                   //查找失败 找到更小的回文
    }
    if (tree[cur].next[let]) {                                      //这个节点已经存在
        suff = tree[cur].next[let];                                 //更新最长前缀值
        return false;
    }

    num++;
    suff = num;
    tree[num].len = tree[cur].len + 2;
    tree[cur].next[let] = num;              //加一个节点

    if (tree[num].len == 1) {               //只有一个X
        tree[num].sufflink = 2;             //指向空串
        tree[num].num = 1;
        return true;
    }

    while (true) {
        cur = tree[cur].sufflink;
        curlen = tree[cur].len;
        if (pos - 1 - curlen >= 0 && s[pos - 1 - curlen] == s[pos]) {
            tree[num].sufflink = tree[cur].next[let];
            break;
        }
    }
    tree[num].num = 1 + tree[tree[num].sufflink].num;
    return true;
}

void initTree() {
    num = 2; suff = 2;
    tree[1].len = -1; tree[1].sufflink = 1;
    tree[2].len = 0; tree[2].sufflink = 1;
}

字典树

struct Trie{
    /**
    *   maxnode:    Trie树中最多可能的节点个数 上限为字符串个数 * 最长长度
    *   sigma_size: 组成字符串的字符种类
    *   ch:         边
    *   value:      节点的值
    *   sz:         Trie树的总节点个数
    */
    int ch[maxnode][sigma_size];
    int value[maxnode];
    int sz;
    int IDX(char c) {return c - 'a';}
    Trie(){
        sz = 1;
        memset(ch[0],0,sizeof(ch[0]));
    }

    /**
    *  字符串s插入Trie中 值为V
    */
    void Insert(char* s,int v){
        int u = 0,len = strlen(s);
        for(int i = 0;i < len;++i){
            int c = IDX(s[i]);
            if(!ch[u][c]){
                memset(ch[sz],0,sizeof(ch[sz]));
                value[sz] = 0;
                ch[u][c] = sz++;
            }
            u = ch[u][c];
        }
        value[u] = v;
    }

    /**
    *   查找字符串s 返回v
    */
    int Search(char* s){
        int cur = 0,idx;
        while(*s){
            idx = IDX(*s);
            if(ch[cur][idx] == 0) return -1;
            cur = ch[cur][idx];
            s++;
        }
        return value[cur];
    }
};

线段树

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

/** 线段树模板 */
/** 以求区间和为例 */
#define lson rt << 1 , l ,mid
#define rson rt << 1 | 1,mid + 1,r
const int maxn = 50000 + 50;
int v[maxn << 2],laze[maxn << 2];
int A[maxn];

// 向下Push laze标记
void PushDown(int rt,int l,int r){
    if(laze[rt]){
        int mid = l + r >> 1,lcnt = mid - l + 1,rcnt = r - mid;
        v[rt << 1] = v[rt << 1] + lcnt * laze[rt];
        v[rt << 1 | 1] = v[rt << 1 | 1] + rcnt * laze[rt];
        laze[rt << 1] += laze[rt];laze[rt << 1 | 1] += laze[rt];
        laze[rt] = 0;
    }
}
//向上更新sum值
void PushUp(int rt){
    v[rt] = v[rt << 1] + v[rt << 1 | 1];
}
void Build(int rt,int l,int r){
    if(l == r){
        v[rt] = A[l];return;
    }
    int mid = l + r >> 1;
    Build(lson),Build(rson);
    laze[rt] = 0;
    PushUp(rt);
}

//将区间L,R 增加X
void Update(int rt,int l,int r,int L,int R,int x){
    if(L <= l && R >= r){
        v[rt] += x * (r - l + 1);
        laze[rt] += x;
        return;
    }
    PushDown(rt,l,r);
    int mid = l + r >> 1;
    if(L <= mid) Update(lson,L,R,x);
    if(R > mid) Update(rson,L,R,x);
    PushUp(rt);
}

int Query(int rt,int l,int r,int L,int R){
    if(L <= l && R >= r){
        return v[rt];
    }
    PushDown(rt,l,r);
    int mid = l + r >> 1;
    int ret = 0;
    if(L <= mid) ret += Query(lson,L,R);
    if(R > mid) ret += Query(rson,L,R);
    PushUp(rt);
    return ret;
}

左偏堆

int key[maxn],dis[maxn],ch[maxn][2];
/**合并以a,b为堆顶的堆*/
int Merge(int a,int b){
    if(!a) return b;if(!b) return a;
    if(key[a] < key[b]) swap(a,b);
    ch[a][1] = Merge(ch[a][1],b);
    if(dis[ch[a][0]] < dis[ch[a][1]]) swap( ch[a][0],ch[a][1] );
    if(ch[a][1] == 0) dis[a] = 0;
    else dis[a] = dis[ch[a][1]] + 1;
    return a;
}

大整数

struct BigInteger{
    int A[25];
    enum{MOD = 10000};
    BigInteger(){memset(A, 0, sizeof(A)); A[0]=1;}
    void set(int x){memset(A, 0, sizeof(A)); A[0]=1; A[1]=x;}
    void print(){
        printf("%d", A[A[0]]);
        for (int i=A[0]-1; i>0; i--){
            if (A[i]==0){printf("0000"); continue;}
            for (int k=10; k*A[i]<MOD; k*=10) printf("0");
            printf("%d", A[i]);
        }
        printf("\n");
    }
    int& operator [] (int p) {return A[p];}
    const int& operator [] (int p) const {return A[p];}
    BigInteger operator + (const BigInteger& B){
        BigInteger C;
        C[0]=max(A[0], B[0]);
        for (int i=1; i<=C[0]; i++)
            C[i]+=A[i]+B[i], C[i+1]+=C[i]/MOD, C[i]%=MOD;
        if (C[C[0]+1] > 0) C[0]++;
        return C;
    }
    BigInteger operator * (const BigInteger& B){
        BigInteger C;
        C[0]=A[0]+B[0];
        for (int i=1; i<=A[0]; i++)
            for (int j=1; j<=B[0]; j++){
                C[i+j-1]+=A[i]*B[j], C[i+j]+=C[i+j-1]/MOD, C[i+j-1]%=MOD;
            }
        if (C[C[0]] == 0) C[0]--;
        return C;
    }
};

快速输入 (整数)

inline bool scan_d(int &num)  
{
        char in;bool IsN=false;
        in=getchar();
        if(in==EOF) return false;
        while(in!='-'&&(in<'0'||in>'9')) in=getchar();
        if(in=='-'){ IsN=true;num=0;}
        else num=in-'0';
        while(in=getchar(),in>='0'&&in<='9'){
                num*=10,num+=in-'0';
        }
        if(IsN) num=-num;
        return true;
}

快速输入 (实数)

inline bool scan_lf(double &num)  
{
        char in;double Dec=0.1;
        bool IsN=false,IsD=false;
        in=getchar();
        if(in==EOF) return false;
        while(in!='-'&&in!='.'&&(in<'0'||in>'9'))
                in=getchar();
        if(in=='-'){IsN=true;num=0;}
        else if(in=='.'){IsD=true;num=0;}
        else num=in-'0';
        if(!IsD){
                while(in=getchar(),in>='0'&&in<='9'){
                        num*=10;num+=in-'0';}
        }
        if(in!='.'){
                if(IsN) num=-num;
                return true;
        }else{
                while(in=getchar(),in>='0'&&in<='9'){
                        num+=Dec*(in-'0');Dec*=0.1;
                }
        }
        if(IsN) num=-num;
        return true;
}

扫描线 √

using namespace std;
const int maxn = 100 + 5;
const int TOT_SEG = maxn * 2;
/** Seg
**  l,r,h 分别为线段的左端点,右端点,高
**  f 标识上下边
*/
struct Seg{
    int f;
    double l,r,h;
    void set(double ll,double rr,double hh,int d){
        l = ll,r = rr,h = hh,f = d;
    }
}Segs[TOT_SEG];
bool cmp(const Seg& a,const Seg& b){
    return a.h < b.h;
}
double AR[TOT_SEG]; /** 区间长度 */
map<double,int> POS; /** 将端点 HASH 到区间上 */
int FALG[TOT_SEG]; /** 区间被覆盖的次数 */
int Seg_CNT,HASH_SEG_CNT;
void SEG_HASH(){
    POS.clear();HASH_SEG_CNT = 2;
    sort(Segs + 1,Segs + Seg_CNT,cmp);
    sort(AR + 1,AR + Seg_CNT);
    for(int i = 2;i < Seg_CNT;++i){
        if(AR[i] != AR[i - 1]){
            AR[HASH_SEG_CNT] = AR[i];
            POS[AR[i]] = HASH_SEG_CNT++;
        }
    }
    for(int i = 1;i < HASH_SEG_CNT;++i){
        AR[i] = AR[i + 1] - AR[i];
    }
}

1~MOD的逆元 √

#define mod 9973ll
typedef long long LL;
LL inv[mod];
inv[1] = 1;
for(int i = 2;i < mod;++i) inv[i] = (mod - mod / i) * (inv[mod % i]) % mod;
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章