模板总结(持续更新)

是时候总结一下了~

其他

离散化

int getid(int x){return lower_bound(v.begin(),v.end(),x) - v.begin() + 1;}
for(int i = 1;i<=n;++i) scanf("%d",&a[i]), v.push_back(a[i]);
sort(v.begin(),v.end()), v.erase(unique(v.begin(),v.end()),v.end());

位运算

统计1的个数

int NumberOfOne(int n) {
    int count = 0;
    while(n) { n &= (n-1); count++;}
    return count;
}

字符串

KMP

void getnext(){
    nxt[0] = -1;
    int k = -1;
    for(int i = 1;i<=lens-1;++i){
        while(k>-1 && str[k+1] != str[i]) k = nxt[k];
        if(str[k+1] == str[i]) k++;
        nxt[i] = k;
    }
}
void kmp(){
    getnext();
    int k = -1;
    for(int i = 0;i<=lent-1;++i){
        while(k>-1&&str[k+1]!=text[i]) k = nxt[k];
        if(str[k+1] == text[i])k++;
        if(k==lens-1){
            ans ++;
            k = -1;
        }
    }
}

Hash

typedef unsigned long long ull;
const ull p = 67;
const ull MOD = 1610612741;
const ull MOD2 = 4294967291;
ull hashstr, pp[nmax] = {0,p};
char str[nmax];
int lenstr;
// 自然溢出
ull hashsub(int l, int r) {
    return hashstr[r] - hashstr[l-1] * pp[r-l+1];
}
void getHash() {
    for (int i = 2; i < nmax; ++i)
        pp[i] = pp[i-1] * p;
    for (int i = 1; i <= lenstr; ++i)
        hashstr[i] = hashstr[i-1] * p + str[i];
}
// 带取模
ull hashsubmod(int l , int r) {
    return ((hashstr[r] - hashstr[l-1] * pp[r-l+1]) % MOD + MOD) % MOD;
}
void getHashMod() {
    for (int i = 2; i < nmax; ++i)
        pp[i] = (pp[i-1] * p) % MOD;
    for (int i = 1; i <= lenstr; ++i)
        hashstr[i] = (hashstr[i-1] * p + str[i]) % MOD;
}

字典树


struct Trie {
    int ch[maxlength][sigma_size];
    int val[maxlength];
    int sz;
    init() { 
        sz = 1; 
        memset(ch[0], 0, sizeof(ch[0])); 
    }
    inline int idx(char c) { return c - 'a'; }

    void insert(char *s, int v) {
        int u = 0, n = strlen(s);
        for(int i = 0; i < n; i++) {
            int c = idx(s[i]);
            if(ch[u][c] == 0) {
                memset(ch[sz], 0, sizeof(ch[sz]));
                ch[u][c] = sz++;
            }
            u = ch[u][c];
            val[u] ++;
        }
    }
    int search(char *s, int v) {
        int u = 0, n = strlen(s), c;
        for(int i = 0; i < n; i++) {
            c = idx(s[i]);
            if(ch[u][c] == 0) return 0;
            u = ch[u][c];
        }
        return val[u];
    }
}trie;

AC自动机

/*  解释:
        nmax是自动机上所有字符的总长度,sigma是字符集大小
        fail表示失配指针,last表示后缀链接
        node[x].isocc表示当前字符是否为单词的结点,node[x].id表示加入自动机的单词编号
        isocc和id可以根据题目做相应调整
    调用:
        aho.init()完成初始化,aho.insert(str)插入单词,aho.build_fail()创建失败指针
        最后使用aho.match(str)完成匹配
*/
const int nmax = 50007;
const int sigma = 128;
struct Aho {
    int sz;
    queue<int> que;
    struct Node {
        int nxt[sigma];
        bool isocc;
        int fail, id, last;
    } node[nmax];

    void init() {
        memset(node[0].nxt, 0, sizeof node[0].nxt);
        sz = 1;
    }

    inline int idx(const char & ch) {return ch;}

    void insert(char * S, int id) {
        int len = strlen(S);
        int now = 0;
        for(int i = 0; i < len; ++i) {
            int c = idx(S[i]);
            if(!node[now].nxt[c]) {
                memset(node[sz].nxt, 0, sizeof node[sz].nxt);
                node[sz].fail = node[now].isocc = node[sz].isocc = 0;
                node[now].nxt[c] = sz++;
            }
            now = node[now].nxt[c];
        }
        node[now].isocc = true;
        node[now].id = id;
    }

    void build_fail() {
        node[0].fail = 0;
        node[0].last = 0;
        for(int i = 0; i < sigma; ++i) {
            if(node[0].nxt[i]) {
                node[node[0].nxt[i]].fail = 0;
                node[node[0].nxt[i]].last = 0;
                que.push(node[0].nxt[i]);
            }
        }
        while(!que.empty()) {
            int now = que.front(); que.pop();
            for(int i = 0; i < sigma; ++i) {
                int son = node[now].nxt[i];
                if(!son) {
                    node[now].nxt[i] = node[node[now].fail].nxt[i];
                    continue;
                }
                que.push(son);
                node[son].fail = node[node[now].fail].nxt[i];
                node[son].last = node[node[now].fail].isocc ? node[son].fail : node[node[son].fail].last;
            }
        }
    }

    void getans(int u) {
        while(u) {
            if(node[u].isocc)
                occ_times[node[u].id] ++;
            u = node[u].last;
        }
    }

    void match(char * S) {
        int len = strlen(S);
        int now = 0;
        for(int i = 0; i < len; ++i) {
            int c = idx(S[i]);
            now = node[now].nxt[c];
            if(node[now].isocc) {
                getans(now);
            } else if(node[now].last) {
                getans(node[now].last);
            }
        }
    }
} aho;

树结构

DFS序

/*  解释:
        pre[x]是原树编号->线段树编号的hash,[pre[x],suf[x]]是原树x表示的区间
        hashback[x]是线段树编号->原树编号的hash
    调用:
        直接dfs(1,-1)即可将树形结构转换成线性结构
    注意:
        建立线段树的时,初始化有2种方法
        1. 建树后直接单点更新,枚举原树一点i,update(pre[i]);
        2. 建树时赋初值,tree[rt].val = initval[hashback[tree[rt].l]];
        关键是原树编号和线段树编号别弄混了
        线段树区间更新的时候,对于原树一点x,update(pre[x],suf[x]);
*/
int pre[nmax], suf[nmax], dfsnum, hashback[nmax], tot;
struct node {int to, nxt;} e[nmax << 1];
void add_edge(int u, int v) { e[tot].to = v, e[tot].nxt = head[u], head[u] = tot++;}
void dfs(int u, int f) {
    pre[u] = ++dfsnum; sz[u] = 1, hashback[dfsnum] = u;
    for (int i = head[u]; i != -1; i = e[i].nxt) if (e[i].to != f) dfs(e[i].to, u);
    suf[u] = dfsnum;
}

树链剖分

/*  解释:
        x的父亲fa[x],x的重儿子son[x],x的深度dep[x],x所在链的顶top[x],x的大小sz[x]
        x的新编号newid[x],原来编号x = hashback[newid[x]],
    调用:
        dfsFirst(1,0,1);
        dfsSecond(1,1);
*/
int fa[nmax], son[nmax], sz[nmax], newid[nmax], hashback[nmax], dep[nmax], top[nmax], head[nmax];
int num, tot;
struct edge {int to, nxt;} e[nmax << 1];
void add(int u, int v) { e[tot].to = v, e[tot].nxt = head[u], head[u] = tot++;}
void init() {
    memset(head, -1, sizeof head);
    memset(son, -1, sizeof son);
    memset(hashback, 0, sizeof hashback);
    tot = num = 0;
}
void dfsFirst(int u, int f, int d) {
    dep[u] = d, fa[u] = f, sz[u] = 1;
    for (int i = head[u]; i != -1; i = e[i].nxt) {
        int v = e[i].to;
        if (v != f) {
            dfsFirst(v, u, d + 1);
            sz[u] += sz[v];
            if (son[u] == -1 || sz[v] > sz[son[u]])  son[u] = v;
        }
    }
}
void dfsSecond(int u, int tp) {
    top[u] = tp, newid[u] = ++num, hashback[num] = u;
    if (son[u] == -1) return;
    dfsSecond(son[u], tp);
    for (int i = head[u]; i != -1; i = e[i].nxt) {
        int v = e[i].to;
        if (v != son[u] && v != fa[u])
            dfsSecond(v, v);
    }
}

树上启发合并

/*
    调用:
        dfs1(1,-1,1)进行第一次dfs求出size和重儿子,dfs2(1,-1)统计答案
    注意:
        在dfs1的时候可以修改,适当做出调整,统计需要的信息,具体情况具体分析
*/
int tot,head[nmax],deep[nmax],sz[nmax],son[nmax];
bool visit[nmax];
struct edge {int to,nxt;} e[nmax<<1];
void add_edge(int u, int v) {e[tot].to = v; e[tot].nxt = head[u]; head[u] = tot++;}
void dfs1(int u, int f, int d) {
    deep[u] = d; sz[u] = 1;
    for(int i = head[u]; i!=-1; i = e[i].nxt) {
        int v = e[i].to;
        if(v != f) {
            dfs1(v,u,d+1); sz[u] += sz[v];
            if(sz[v] > sz[son[u]]) son[u] = v;
        }
    }
}
void update(int u, int f){
    // 统计答案
    cnt[deep[u]] ^= (1<<(letter[u] - 'a'));
    // 遍历儿子
    for(int i = head[u];i!=-1;i=e[i].nxt){
        int v = e[i].to;
        if(v != f && !visit[v]) update(v,u);
    }
}
void dfs2(int u, int f, bool keep = false) {
    for(int i = head[u]; i!=-1; i = e[i].nxt) {
        int v = e[i].to;
        if(v == f || v == son[u]) continue;
        else dfs2(v,u);
    }
    if(son[u]) dfs2(son[u],u,true), visit[son[u]] = true;
    // 计算当前节点答案
    update(u,f);
    // 统计答案:可以是直接统计,也可以是遍历所有询问统计
    // 遍历所有询问:for(int i = qhead[u] ; i!=-1; i = query[i].nxt) query[i].ans = countone(cnt[query[i].to]);
    // 直接统计: ans[i] = nowans;
    if(son[u]) visit[son[u]] = false;
    // 如果是轻儿子,则清楚轻儿子的答案
    if(!keep) update(u,f); 
}

图论部分

强连通分量

/*解释:
     color表示染色,sz表示每个连通分量的大小,sccnum表示强连通分量个数
     in和out用于统计缩点后的图每个连通分量的入度和出度
  调用:
     首先调用init(vertexnum),之后add_edge(u,v)加边,最后start(运行算法)
     如果必要可以调用get_ans()来对缩点后的图进行遍历,统计答案
*/
struct Tarjan {
    int head[nmax], low[nmax], dfn[nmax], sstack[nmax], color[nmax], sz[nmax], top, sccnum, dfnnum, tot, n;
    int in[nmax], out[nmax];
    bool visit[nmax];
    struct edge {int to, nxt;} e[nmax << 1];
    void init(int n) {
        memset(head, -1, sizeof head);
        memset(mincost, INF, sizeof mincost);
        memset(dfn, 0, sizeof dfn);
        memset(color, 0, sizeof color);
        memset(visit, 0, sizeof visit);
        memset(sz, 0, sizeof sz);
        memset(in, 0, sizeof in);
        memset(out, 0, sizeof out);
        cnt = dfnnum = top = sccnum = tot = 0;
        this->n = n;
    }
    void add_edge(int u, int v) {
        e[tot].to = v, e[tot].nxt = head[u]; head[u] = tot++;
    }
    void tarjan(int u) {
        low[u] = dfn[u] = ++dfnnum;
        visit[u] = true;
        sstack[++top] = u;
        for (int i = head[u] ; i != -1; i = e[i].nxt) {
            int v = e[i].to;
            if (!dfn[v]) {
                tarjan(v);
                low[u] = min(low[u], low[v]);
            } else if (visit[v]) low[u] = min(low[u], dfn[v]);
        }
        if (dfn[u] == low[u]) {
            visit[u] = false;
            color[u] = ++ sccnum;
//            printf("scc %d %d",sccnum,u);
            sz[sccnum]++;
            mincost[sccnum] = min(mincost[sccnum], cost[u]);
            while (sstack[top] != u) {
//                printf(" %d",sstack[top]);
                color[sstack[top]] = sccnum;
                sz[sccnum]++;
                visit[sstack[top]] = false;
                mincost[sccnum] = min(mincost[sccnum], cost[sstack[top]]);
                top--;
            }
//            printf("\n");
            top--;
        }
    }
    void dfs(int u) {
        visit[u] = true;
        for (int i = head[u]; i != -1; i = e[i].nxt) {
            int v = e[i].to;
            if (!visit[v]) {
                if (color[v] != color[u]) in[color[v]]++, out[color[u]]++;
                dfs(v);
            } else if (visit[v]) {
                if (color[v] != color[u]) in[color[v]]++, out[color[u]]++;
            }
        }
    }
    void start() {for (int i = 1; i <= n; ++i) if (!dfn[i]) tarjan(i);}
    void get_ans() {
        memset(visit, 0, sizeof visit);
        for (int i = 1; i <= n; ++i) if (!visit[i]) dfs(i);
        for (int i = 1; i <= sccnum; ++i) {
            //统计答案
        }
    }
} solver;

割点

/*解释:
    如果为割点iscut[i] = 1, cutnum[i]表示去掉点i新增的(连通分量数目值-1)
    scc表示整张图的连通分量个数,n表示图的点数
  调用:
    先init(vertexnum);之后add_edge(u,v)加边;最后start()
*/
struct edge{
    int nxt,to;
};
struct Cut_Tarjan{
    int dfn[nmax],low[nmax],cutnum[nmax],head[nmax],dfs_clock,n,scc,tot;
    bool iscut[nmax];
    edge e[nmax<<1];
    void add_edge(int u, int v){
        e[tot].to = v, e[tot].nxt = head[u];
        head[u] = tot++;
    }
    void init(int n){
        memset(head,-1,sizeof head);
        memset(dfn,0,sizeof dfn);
        memset(cutnum,0,sizeof cutnum);
        memset(iscut,0,sizeof iscut);
        dfs_clock = tot = scc = 0;
        this->n = n;
    }
    void dfs(int u,int fa){
        int child = 0;
        low[u] = dfn[u] = ++dfs_clock;
        for(int i = head[u];i!=-1;i = e[i].nxt){
            int v = e[i].to;
            if(v != fa){
                if(!dfn[v]){
                    child ++;
                    dfs(v,u);
                    low[u] = min(low[u],low[v]);
                    if(fa != -1 && low[v] >= dfn[u]) cutnum[u] ++,iscut[u] = true;
                }else if(dfn[v]<low[u]) low[u] = min(low[u],dfn[v]);
            }
        }
        if(fa == -1 && child > 1) iscut[u] = true;
        if(fa == -1) cutnum[u] = child - 1;
    }
    void start(){
        for(int i = 1;i<=n;++i) if(!dfn[i]) dfs(i,-1),scc++;
    }
}cut_t;

网络流最大流

/*解释:
    iscut用来判断是否是最小割,方法如下
    在残量网络中,容量大于0表示可以走。将从源点出发可以到达的点看作S集,剩下的看作T集。
    如果边(u,v)满足u属于S集,v属于T集,那么该边就是最小割边集中的边。
    n为网络中的点数(如果0在图中的话不算),cur是当前弧优化
 调用:
     首先init(vertexnum);之后add_edge(u,v,c)建图;最后Maxflow(S,T);需要时可以getcut。
 注意:
     如果流量超过了int,记得换long long.
*/
struct Dinic {
    int head[nmax], cur[nmax], d[nmax];
    bool vis[nmax],iscut[nmax];
    int tot, n, m, s, t;
    struct edge {
        int nxt, to, w, cap, flow;
    } e[nmax<<1];
    void init(int n) {
        this->n = n;
        this->tot = 0;
        memset(head, -1, sizeof head);
        memset(iscut,0,sizeof iscut);
    }
    void add_edge(int u, int v, int c) {
        e[tot].to = v, e[tot].cap = c, e[tot].flow = 0;
        e[tot].nxt = head[u];
        head[u] = tot++;
        e[tot].to = u, e[tot].cap = c, e[tot].flow = c;
        e[tot].nxt = head[v];
        head[v] = tot++;
    }
    bool BFS() {
        memset(vis, 0, sizeof(vis));
        queue<int>Q;
        vis[s] = 1; d[s] = 0;
        Q.push(s);
        while (!Q.empty()) {
            int u = Q.front(); Q.pop();
            for (int i = head[u]; i != -1; i = e[i].nxt) {
                int v = e[i].to;
                if (!vis[v] && e[i].cap > e[i].flow) {
                    vis[v] = 1;
                    d[v] = d[u] + 1;
                    Q.push(v);
                }
            }
        }
        return vis[t];
    }
    int DFS(int x, int a) {
        if (x == t || a == 0) return a;
        int Flow = 0, f;
        for (int& i = cur[x]; i != -1; i = e[i].nxt) {
            int v = e[i].to;
            if (d[v] == d[x] + 1 && (f = DFS(v, min(a, e[i].cap - e[i].flow))) > 0) {
                Flow += f;
                e[i].flow += f;
                e[i ^ 1].flow -= f;
                a -= f;
                if (a == 0) break;
            }
        }
        return Flow;
    }
    int Maxflow(int s, int t) {
        this->s = s, this->t = t;
        int Flow = 0;
        while (BFS()) {
            for (int i = 0; i <= n; i++) cur[i] = head[i];
            while(int once = DFS(s, INF)) Flow += once;
        }
        return Flow;
    }
    void get_cut(int u){
        iscut[u] = true;
        for (int i = head[u]; i != -1; i = e[i].nxt) {
            int v = e[i].to;
            if (!iscut[v] && e[i].cap > e[i].flow)
                get_cut(v);
        }
        return;
    }
} dinic;

最小费用最大流

struct MCMF{
    int final_flow,final_cost,tot,S,T;
    bool inque[nmax];
    int head[nmax],dis[nmax],pre_edge[nmax],pre_index[nmax],add_flow[nmax];
    struct edge{ int to,nxt,cap,flow,cost;}e[nmax<<1];
    void init(int S, int T){
        memset(head,-1,sizeof head);
        this->S = S, this->T = T;
    }
    void add_edge(int u, int v, int cap, int cost){
        e[tot].to = v, e[tot].nxt = head[u], e[tot].flow = 0, e[tot].cap = cap, e[tot].cost = cost, head[u] = tot++;
        e[tot].to = u, e[tot].nxt = head[v], e[tot].flow = 0, e[tot].cap = 0, e[tot].cost = -cost, head[v] = tot++;
    }
    bool spfa(){
        for(int i = S;i<=T;++i) inque[i] = false, dis[i] = i == S?0:INF;
        queue<int> q; q.push(S), inque[S] = true, add_flow[S] = INF;
        while(!q.empty()){
            int u = q.front(); q.pop(); inque[u] = false;
            for(int i = head[u];i!=-1;i=e[i].nxt){
                int v = e[i].to;
                if(e[i].cap > e[i].flow && dis[u] + e[i].cost < dis[v]){
                    dis[v] = dis[u] + e[i].cost, pre_edge[v] = i, pre_index[v] = u;
                    add_flow[v] = min(add_flow[u],e[i].cap - e[i].flow);
                    if(!inque[v]) q.push(v),inque[v] = true;
                }
            }
        }
        return dis[T] != INF;
    }
    void mincost_mxflow() {
        final_cost = final_flow = 0;
        while(spfa()){
            final_flow += add_flow[T];
            final_cost += add_flow[T] * dis[T];
            int now = T;
            while(now != S){
                e[pre_edge[now]].flow += add_flow[T];
                e[pre_edge[now]^1].flow -= add_flow[T];
                now = pre_index[now];
            }
        }
    }
}solver;

二分图最佳完美匹配

/*解释:见代码
  调用:
    初始化init(vertexnum);对edge直接进行修改;调用Perfect_Match()进行匹配。
  注意:
    默认求解最大权值匹配,如果需要求解最小,需要将edge取负,最后结果再取负即可。
*/
struct KM{
    bool mp[size][size];            // 二分图的相等子图, mp[i][j] = true 代表Xi与Yj有边
    bool xckd[size], yckd[size];    // 标记在一次DFS中,Xi与Yi是否在交错树上
    int match[size];                // 保存匹配信息,其中i为Y中的顶点标号,match[i]为X中顶点标号
    int n, edge[size][size];        // edge[i][j]为连接Xi与Yj的边的权值
    void Perfect_Match() {
        int i, j;
        int lx[size], ly[size];     // KM算法中Xi与Yi的标号
        for(i = 0; i < n; i++) {
            lx[i] = -INF;
            ly[i] = 0;
            for(j = 0; j < n; j++)
                lx[i] = max(lx[i], edge[i][j]);
        }
        bool perfect = false;
        while(!perfect) {
            for(i = 0; i < n; i++)  // 初始化邻接矩阵
                for(j = 0; j < n; j++)
                    if(lx[i]+ly[j] == edge[i][j]) mp[i][j] = true;
                    else mp[i][j] = false;
            int live = 0;           // 匹配过程
            memset(match, -1, sizeof(match));
            for(i = 0; i < n; i++) {
                memset(xckd, false, sizeof(xckd));
                memset(yckd, false, sizeof(yckd));
                if(DFS(i, n))live++;
                else {
                    xckd[i] = true;
                    break;
                }
            }
            if(live == n) perfect = true;
            else {
                int ex = INF;// 修改标号过程
                for(i = 0; i < n; i++)
                    for(j = 0; xckd[i] && j < n; j++)
                        if(!yckd[j]) ex = min(ex, lx[i]+ly[j]-edge[i][j]);
                for(i = 0; i < n; i++) {
                    if(xckd[i]) lx[i] -= ex;
                    if(yckd[i]) ly[i] += ex;
                }
            }
        }
    }
    bool DFS(int p, const int n) { // 此函数用来寻找是否有以Xp为起点的增广路径,返回值为是否含有增广路
        for(int i = 0; i < n; i++) {
            if(!yckd[i] && mp[p][i]) {
                yckd[i] = true;
                int t = match[i];
                match[i] = p;
                if(t == -1 || DFS(t, n)) return true;
                match[i] = t;
                if(t != -1) xckd[t] = true;
            }
        }
        return false;
    }
    void init(int n){
        memset(edge,0,sizeof edge);
        this->n = n;
    }
}km;

数学部分

线性基

/*  解释:
        iszero表示线性基中是否异或后是否有0
    使用:
        insert(x)向线性基中插入数值,如果需要查询第k大,需要rebuild()
*/
struct L_B {
    ll d[61], p[61];
    int cnt;
    bool iszero;
    L_B() {
        memset(d, 0, sizeof(d));
        memset(p, 0, sizeof(p));
        iszero = cnt = 0;
    }
    void clear() {
        memset(d, 0, sizeof(d));
        memset(p, 0, sizeof(p));
        iszero = cnt = 0;
    }
    bool insert(ll val) {
        for (int i = 60; i >= 0; i--)
            if (val & (1LL << i)) {
                if (!d[i]) { d[i] = val; break;}
                val ^= d[i];
            }
        if (val == 0) iszero = true;
        return val > 0;
    }
    ll query_max() {
        ll ret = 0;
        for (int i = 60; i >= 0; i--) if ((ret ^ d[i]) > ret) ret ^= d[i];
        return ret;
    }
    ll query_min() {
        if (iszero) return 0LL;
        for (int i = 0; i <= 60; i++) if (d[i]) return d[i];
        return 0;
    }
    void rebuild() {
        for (int i = 60; i >= 0; i--)
            for (int j = i - 1; j >= 0; j--)
                if (d[i] & (1LL << j)) d[i] ^= d[j];
        for (int i = 0; i <= 60; i++) if (d[i]) p[cnt++] = d[i];
    }
    ll kthquery(ll k) {
        if (iszero) k--;
        ll ret = 0;
        if (k >= (1LL << cnt)) return -1;
        for (int i = 60; i >= 0; i--) if (k & (1LL << i)) ret ^= p[i];
        return ret;
    }
} lb;

离线算法

普通莫队

/*  解释:
        belong[x]x属于分块后的哪一块,Q[i]每个询问
        modify(p,t)对p位置进行t修改,一般只有增加或者缩减这两种操作,具体问题具体分析
    注意:
        最后也可以不对询问id排序,直接保存到一个数组里面输出即可
*/
int a[nmax], belong[nmax];
ll ans = 0;
struct node {int l, r, id;ll ans;} Q[nmax];
bool cmp(node a, node b) {
    if (belong[a.l] != belong[b.l]) return a.l < b.l;
    else return a.r < b.r;
}
bool cmpid(node a, node b) {return a.id < b.id;}
void modify(int pos, int tag) {
    // ......... 增删操作
}
int main() {
    scanf("%d %d", &n, &m);
    int sz = sqrt(n);
    for (int i = 1; i <= n; ++i) scanf("%d", &a[i]);
    for (int i = 1; i <= m; ++i) {
        scanf("%d %d", &Q[i].l, &Q[i].r), Q[i].id = i;
        belong[i] = (i - 1) / sz + 1;
    }
    sort(Q + 1, Q + 1 + m, cmp);
    int l = 1, r = 0;
    for (int i = 1; i <= m; ++i) {
        while (l < Q[i].l) modify(l++, -1);
        while (l > Q[i].l) modify(--l, 1);
        while (r > Q[i].r) modify(r--, -1);
        while (r < Q[i].r) modify(++r, 1);
        Q[i].ans = ans;
    }
    sort(Q + 1, Q + 1 + m, cmpid);
    for (int i = 1; i <= m; ++i) printf("%I64d\n", Q[i].ans);
    return 0;
}

RMQ

int dp[nmax][(int) (log2(nmax) + 10)];
int a[nmax];
void getRMQ() {
    for (int i = 1; i <= n; ++i)
        dp[i][0] = a[i];
    for (int j = 1; (1 << j) <= n ; ++j)
        for (int i = 1; i + ( 1 << j ) - 1 <= n; ++i)
            dp[i][j] = max(dp[i][j - 1], dp[i + (1 << (j - 1 ))][j - 1]);
}
int RMQmax(int l, int r) {
    int k = 0;
    while ( (1 << (k + 1)) <= r - l + 1) ++k;
    return max(dp[l][k], dp[r - (1 << k) + 1][k]);
}

猜你喜欢

转载自blog.csdn.net/pengwill97/article/details/81363245