算法模板

一、动态规划

1. 状态压缩DP

AcWing 1064. 小国王

在 n×n 的棋盘上放 k 个国王,国王可攻击相邻的 8 个格子,求使它们无法互相攻击的方案总数。

复制代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 12;
ll f[N][1<<N][N*N];
int n,K,num[1<<N],p[1<<N],cnt;
int count(int x){
    int res = 0;
    while(x){
        if(x&1)res++;
        x>>=1;
    }
    return res;
}
bool pd(int x,int y,bool flg){
    if((flg&&(x&y)) || (x&(y>>1)) || (x&(y<<1)))return false;
    else return true;
}
int main(){
    cin>>n>>K;
    for(int i = 0;i<(1<<n);++i){
        num[i] = count(i);
        if(pd(i,i,0))p[++cnt] = i;
    }
    f[0][1][0] = 1;
    for(int i = 1;i<=n+1;++i){
        for(int j = 1;j<=cnt;++j){
                for(int k = 0;k<=K;++k){
                if(num[p[j]] > k)continue;
                for(int t = 1;t<=cnt;++t){
                    if(!pd(p[j],p[t],1))continue;
                    f[i][j][k] += f[i-1][t][k-num[p[j]]];
                }
            }
        }
    }
    cout<<f[n+1][1][K]<<'\n';
    return 0;
}
复制代码

2. 树形DP

AcWing 1072. 树的最长路径

给定一棵树,树中包含 n 个结点(编号1~n)和 n−1 条无向边,每条边都有一个权值。
现在请你找到树中的一条最长路径。

复制代码
#include<bits/stdc++.h>
using namespace std;
const int N = 2e4 + 10,inf = 0x3f3f3f3f;
int h[N],w[N],e[N],ne[N],idx;
int n,f1[N],f2[N],g[N],id[N];
void add(int a,int b,int c){
    e[idx] = b,w[idx] = c,ne[idx] = h[a],h[a] = idx++;
}
void pre_dfs(int u,int fa){
    for(int i = h[u];~i;i=ne[i]){
        int j = e[i],c = w[i];
        if(j == fa)continue;
        pre_dfs(j,u);
        if(f1[j]+c>f1[u]){
            f2[u] = f1[u];
            f1[u] = f1[j]+c;
            id[u] = j;
        }
        else if(f1[j]+c>f2[u]){
            f2[u] = f1[j]+c;
        }
    }
}
void dfs(int u,int fa){
    for(int i = h[u];~i;i=ne[i]){
        int j = e[i],c = w[i];
        if(j == fa)continue;
        if(id[u] == j){
            g[j] = max(g[u] + c, f2[u] + c);
        }
        else{
            g[j] = max(g[u] + c, f1[u] + c);
        }
        dfs(j,u);
    }
}
int main(){
    memset(h,-1,sizeof h);
    cin>>n;
    for(int i = 1;i<=n-1;++i){
        int a,b,c;
        cin>>a>>b>>c;
        add(a,b,c);
        add(b,a,c);
    }
    pre_dfs(1,0);
    dfs(1,0);
    int res = 0;
    for(int i = 1;i<=n;++i){
        res = max({res,f1[i]+f2[i],f1[i]+g[i]});
    }
    cout<<res<<'\n';
    return 0;
}
复制代码

3. 数位DP

不吉利的数字为所有含有 4 或 62 的号码。

你的任务是,对于每次给出的一个牌照号区间 [n,m],推断出交管局今后又要实际上给多少辆新的士车上牌照了。

复制代码
#include<bits/stdc++.h>
using namespace std;
const int N = 15;
int f[N][N];
void init(){
    f[0][0] = 1;
    for(int i = 0;i<=9;++i)if(i!=4)f[1][i]++;
    for(int i = 2;i<N;++i){
        for(int j = 0;j<=9;++j){
            for(int k = 0;k<=9;++k){
                if(j==4 || k==4)continue;
                if(j==6 && k==2)continue;
                f[i][j] += f[i-1][k];
            }
        }
    }
}
int dp(int n){
    if(!n)return 1;
    vector<int> v;
    while(n>0)v.push_back(n%10),n/=10;
    int last = 0,res = 0;
    for(int i = v.size() - 1;i>=0;--i){
        int x = v[i];
        for(int j = 0;j<x;++j){
            if(j == 4)continue;
            if(last==6 && j==2)continue;
            for(int k = 0;k<=9;++k){
                if(k == 4)continue;
                if(j==6 && k==2)continue;
                res += f[i][k];
            }
        }
        if(x==4 || last==6&&x==2)break;
        last = x;
        if(!i)++res;
    }
    return res;
}
int main(){
    int l,r;
    init();
    while(cin>>l>>r&&(l||r)){
        cout<<dp(r) - dp(l-1)<<'\n';    
    }
    
    return 0;
}
复制代码

4.  单调队列优化DP

AcWing 135. 最大子序和 

输入一个长度为 n 的整数序列,从中找出一段长度不超过 m 的连续子序列,使得子序列中所有数的和最大。

复制代码
#include<bits/stdc++.h>
using namespace std;
const int N = 3e5 + 10,inf = 99999999999;
int a[N],s[N],q[N];
int main(){
    int n,m;
    cin>>n>>m;
    for(int i = 1;i<=n;++i)cin>>a[i],s[i]=s[i-1]+a[i];
    int hh = 0,tt = 0,res = -inf;
    for(int i = 1;i<=n;++i){
        while(q[hh]<i-m)++hh;
        res = max(res,s[i]-s[q[hh]]);
        while(hh<=tt&&s[q[tt]]>=s[i])--tt;
        q[++tt] = i;
    }
    cout<<res;
    return 0;
}
复制代码

5. 斜率优化DP

AcWing 301. 任务安排2 

有 N 个任务排成一个序列在一台机器上等待执行,它们的顺序不得改变。
机器会把这 N 个任务分成若干批,每一批包含连续的若干个任务。
从时刻 0 开始,任务被分批加工,执行第 i 个任务所需的时间是 Ti。
另外,在每批任务开始前,机器需要 S 的启动时间,故执行一批任务所需的时间是启动时间 S 加上每个任务所需时间之和。
一个任务执行后,将在机器中稍作等待,直至该批任务全部执行完毕。
也就是说,同一批任务将在同一时刻完成。
每个任务的费用是它的完成时刻乘以一个费用系数 Ci。
请为机器规划一个分组方案,使得总费用最小。

复制代码
#include<bits/stdc++.h>
using namespace std;
const int N = 3e5 + 10;
typedef long long ll;
ll t[N],c[N],f[N],s,n,q[N];
int main(){
    cin>>n>>s;
    for(int i = 1;i<=n;++i){
        cin>>t[i]>>c[i];
        t[i]+=t[i-1];c[i]+=c[i-1];
    }
    int hh=0,tt=0;
    for(int i = 1;i<=n;++i){
        while(hh<tt&&(f[q[hh+1]]-f[q[hh]])<=(s+t[i])*(c[q[hh+1]]-c[q[hh]]))++hh;
        int j = q[hh];
        f[i] = f[j] - c[j]*(s+t[i]) + c[i]*t[i]+s*c[n];
        while(hh<tt&&(f[q[tt]]-f[q[tt-1]])*(c[i]-c[q[tt]])>=(f[i]-f[q[tt]])*(c[q[tt]]-c[q[tt-1]]))--tt;
        q[++tt] = i;
    }
    cout<<f[n];
    return 0;
}
复制代码

二、搜索

1.A*

AcWing 178. 第K短路

复制代码
#include<bits/stdc++.h>
using namespace std;
#define x first
#define y second
const int N = 1010,inf = 0x3f3f3f3f;
typedef pair<int,int> PII;
typedef pair<int,PII> PIII;
int n,m,f[N],S,T,K;
vector<PII>v[N],vt[N];
void dijkstra(){
    bool vis[N];
    priority_queue<PII,vector<PII>,greater<PII> >Q;
    memset(f,inf,sizeof f);
    memset(vis,0,sizeof vis);
    f[T] = 0;
    Q.push({0,T});
    while(Q.size()){
        auto t = Q.top();
        Q.pop();
        if(vis[t.y])continue;
        vis[t.y] = 1;
        for(auto&[to,w]:vt[t.y]){
            if(w+f[t.y]<f[to]){
                f[to] = w + f[t.y];
                Q.push({f[to],to});
            }
        }
    }
}
int bfs(){
    if(S==T)++K;
    int cnt[N];
    memset(cnt,0,sizeof cnt);
    priority_queue<PIII,vector<PIII>,greater<PIII> >Q;
    Q.push({f[S],{0,S}});
    while(Q.size()){
        auto t = Q.top();
        Q.pop();
        cnt[t.y.y]++;
        int u = t.y.y,d = t.y.x;
        if(u==T && cnt[u]>=K)return d;
        for(auto&[to,w]:v[u]){
            if(cnt[to]<=K)
            Q.push({d+w+f[to],{d+w,to}});
        }
    }
    return -1;
}
int main(){
    cin>>n>>m;
    for(int i = 1;i<=m;++i){
        int a,b,l;
        cin>>a>>b>>l;
        v[a].push_back({b,l});
        vt[b].push_back({a,l});
    }
    cin>>S>>T>>K;
    dijkstra();
    int ans = bfs();
    cout<<ans;
    return 0;
}
复制代码

2.双向广搜

已知有两个字串 A, B 及一组字串变换的规则(至多 6 个规则):

若在 10 步(包含 10 步)以内能将 A 变换为 B ,则输出最少的变换步数;否则输出 NO ANSWER!。

复制代码
#include<bits/stdc++.h>
using namespace std;
const int N = 110;
int n = 0;
string a[N],b[N];
string A,B;
int extend(queue<string>&qa,unordered_map<string,int>&ma,unordered_map<string,int>&mb,string a[],string b[]){
    int d = ma[qa.front()];
    while(qa.size() && ma[qa.front()] == d){
        string str = qa.front();
        qa.pop();
        for(int i = 0;i<n;++i){
            for(int j = 0;j+a[i].size()<=str.size();++j){
                if(str.substr(j,a[i].size())==a[i]){
                    string g = str.substr(0,j) + b[i] + str.substr(j+a[i].size());
                    if(mb.count(g))return ma[str] + mb[g] + 1;
                    if(ma.count(g))continue;
                    ma[g] = ma[str] + 1;
                    qa.push(g);
                }
            }
        }
    }
    return 11;
}
int bfs(){
    if(A==B){
        return 0;
    }
    int step = 0;
    queue<string> qa,qb;
    qa.push(A);qb.push(B);
    unordered_map<string,int>ma,mb;
    ma[A] = mb[B] = 0;
    while(qa.size()&&qb.size()){
        int res;
        if(qa.size()<qb.size())res = extend(qa,ma,mb,a,b);
        else res = extend(qb,mb,ma,b,a);
        if(res <= 10)return res;
        if(++step>10)break;
    }
    return -1;
}
int main(){
    cin>>A>>B;
    while(cin>>a[n]>>b[n])++n;
    int ans = bfs();
    if(ans!=-1)cout<<ans;
    else cout<<"NO ANSWER!"<<'\n';
    return 0;
}
复制代码

3.IDA*

给定 n 本书,编号为 1∼n。

在初始状态下,书是任意排列的。

在每一次操作中,可以抽取其中连续的一段,再把这段插入到其他某个位置。

我们的目标状态是把书按照 1∼n 的顺序依次排列。

求最少需要多少次操作。

复制代码
#pragma GCC optimize("Ofast", "inline", "-ffast-math")
#pragma GCC target("avx,sse2,sse3,sse4,mmx")
#include<bits/stdc++.h>
using namespace std;
typedef vector<int> VI;
#define x first
#define y second
typedef pair<VI,int> P;
const int N = 16;
int n,a[N];
int lst[2][N];
int f(vector<int> &v,bool b){
    int res = 0;
     for(int i = 0;i+1<n;++i){
        if(v[i+1]!=lst[b][v[i]])++res;
    }
    res += (0!=lst[b][v[n-1]]);
    return res;
}
int extend(queue<P> &qa,map<VI,int>&da,map<VI,int>&db,bool b){
    int d = qa.front().y;
    while(qa.size() && qa.front().y == d){
        
        auto t = qa.front();
        VI v = t.x;
        qa.pop();
        if(f(v,b)+d>=5)continue;
        for(int l = 0;l<n;++l){
            for(int r = l;r+1<n;++r){
                for(int k = r+1;k<n;++k){

                    VI to(n);
                    int t = 0;
                    for(int i = 0;i<l;++i)to[t++] = v[i];
                    for(int i = r+1;i<=k;++i)to[t++] = v[i];
                    for(int i = l;i<=r;++i)to[t++] = v[i];
                    for(int i = k+1;i<n;++i)to[t++] = v[i];

                   
                    if(da.count(to))continue;
                    qa.push({to,d+1});
                    da[to] = d + 1;
                    
                    if(db.count(to)){
                        return db[to] + d + 1;
                    }
                    
                }
            }
        }
    }
    return -1;
}
int bfs(){
    queue<P> qa,qb;
    map<VI,int>da,db;
    VI sa,sb;
    for(int i = 0;i<n;++i)sa.push_back(a[i]),lst[0][a[i]] = a[i+1];
    for(int i = 0;i<n;++i)sb.push_back(i+1),lst[1][i+1] = i+2;
    lst[1][n] = 0;
    qa.push({sa,0});
    da[sa] = 0;
    qb.push({sb,0});
    db[sb] = 0;
    int dep = 0;
    if(sa == sb){
        return 0;
    }
    while(qa.size() && qb.size()){ 
        int d;
        if(qa.size()<qb.size())d = extend(qa,da,db,0);
        else d = extend(qb,db,da,1);
        if(d!=-1)return d;
        ++dep;
        if(dep==4)break;
    }
    return -1;
}
int main(){
    //freopen("a.txt","r",stdin);
    int T;
    cin>>T;
    while(T--){
        cin>>n;
        for(int i = 0;i<n;++i)cin>>a[i];
        int ans = bfs();
        if(ans==-1)puts("5 or more");
        else cout<<ans<<'\n';
    }
    return 0;
    
}
复制代码

三、图论

1.有向图的强连通分量

每一头牛的愿望就是变成一头最受欢迎的牛。

现在有 N 头牛,编号从 1 到 N,给你 M 对整数 (A,B),表示牛 A 认为牛 B 受欢迎。

这种关系是具有传递性的,如果 A 认为 B 受欢迎,B 认为 C 受欢迎,那么牛 A 也认为牛 C 受欢迎。

你的任务是求出有多少头牛被除自己之外的所有牛认为是受欢迎的。

复制代码
#include<bits/stdc++.h>
using namespace std;
const int N = 10010;
vector<int> G[N];
int dfn[N],low[N],stk[N],top;
int scc_cnt,sz[N],dout[N],id[N];
int n,m,cnt = 0;
bool is_stk[N];
void tarjan(int u){
    dfn[u] = low[u] = ++cnt;
    stk[++top] = u;
    is_stk[u] = true;
    for(auto to:G[u]){
        if(!dfn[to]){
            tarjan(to);
            low[u] = min(low[to],dfn[u]);
        }
        else if(is_stk[to]){
            low[u] = min(low[u],low[to]);
        }
    }
    if(dfn[u] == low[u]){
        int y;
        scc_cnt++;
        do{
            y = stk[top--];
            is_stk[u] = false;
            id[y] = scc_cnt;
            sz[scc_cnt]++;
        }
        while(y!=u);
    }
}
bool vis[N];
int main(){
    cin>>n>>m;
    for(int i = 1;i<=m;++i){
        int a,b;
        cin>>a>>b;
        G[a].push_back(b);
    }
    for(int i = 1;i<=n;++i)
    if(!dfn[i])tarjan(i);
    for(int i = 1;i<=n;++i){
        for(auto to:G[i]){
            if(id[i] != id[to])
            dout[id[i]]++;
        }
    }
    int ans = 0,zeros = 0;
    for(int i = 1;i<=scc_cnt;++i){
        if(!dout[i]){
            ++zeros;
            ans = sz[i];
            if(zeros>1){
                ans = 0;
                break;
            }
        }
    }
    cout<<ans;
    return 0;
}
复制代码

2.无向图的双连通分量

1)桥

为了从 F 个草场中的一个走到另一个,奶牛们有时不得不路过一些她们讨厌的可怕的树。

奶牛们已经厌倦了被迫走某一条路,所以她们想建一些新路,使每一对草场之间都会至少有两条相互分离的路径,这样她们就有多一些选择。

每对草场之间已经有至少一条路径。

给出所有 R 条双向路的描述,每条路连接了两个不同的草场,请计算最少的新建道路的数量,路径由若干道路首尾相连而成。

两条路径相互分离,是指两条路径没有一条重合的道路。

但是,两条分离的路径上可以有一些相同的草场。

对于同一对草场之间,可能已经有两条不同的道路,你也可以在它们之间再建一条道路,作为另一条不同的道路。

复制代码
#include<bits/stdc++.h>
using namespace std;
const int N = 5010,M = 2e4+10;
int h[M],e[M],idx,ne[M],n,m;
int stk[N],dfn[N],low[N],scc_cnt,timestamp;
bool is_stk[N],is_brige[M];
int id[N],top,d[N];
void add(int a,int b){
    e[idx] = b,ne[idx] = h[a],h[a] = idx++;
}
void tarjan(int u,int fr){
    dfn[u] = low[u] = ++timestamp;
    stk[++top] = u;
    for(int i = h[u];~i;i=ne[i]){
        int j = e[i];
        if(!dfn[j]){
            tarjan(j,i);
            low[u] = min(low[u],low[j]);
            if(low[j]>low[u]){
                is_brige[i] = true;
                is_brige[i^1] = true;
            }
        }
        else if(i != (fr^1)){
            low[u] = min(low[u],dfn[j]);
        }
    }
    if(dfn[u] == low[u]){
        int y;
        ++scc_cnt;
        do{
            y = stk[top--];
            id[y] = scc_cnt;
        }while(y!=u);
    }
}
int main(){
    cin>>n>>m;
    memset(h,-1,sizeof h);
    for(int i = 1;i<=m;++i){
        int a,b;
        cin>>a>>b;
        add(a,b);
        add(b,a);
    }
    tarjan(1,-1);
    for(int i = 0;i<idx;++i){
        if(is_brige[i]){
            d[id[e[i]]]++;
        }
    }
    int ans = 0;
    for(int i = 1;i<=scc_cnt;++i){
        if(d[i]==1)++ans;
    }
    cout<<(ans+1)/2;
    return 0;
}
复制代码

2)割点

复制代码
#include<bits/stdc++.h>
using namespace std;
const int N = 1e4+10;
vector<int> G[N];
int low[N],dfn[N],ans;
int n,m,root,timestamp;
void tarjan(int u){
    dfn[u] = low[u] = ++timestamp;
    int cnt = 0;
    for(auto to:G[u]){
        if(!dfn[to]){
            tarjan(to);
            low[u] = min(low[u],low[to]);
            if(low[to] >= dfn[u])++cnt;
        }
        else low[u] = min(low[u],dfn[to]);
    }
    if(u != root)++cnt;
    ans = max(ans,cnt);

}
int main(){
    while(cin>>n>>m,n||m){
        ans = 0;
        timestamp = 0;
        memset(dfn,0,sizeof dfn);
        for(int i = 0;i<n;++i)G[i].clear();
        for(int i = 1;i<=m;++i){
            int a,b;
            cin>>a>>b;
            G[a].push_back(b);
            G[b].push_back(a);
        }
        int cnt = 0;
        for(root = 0;root<n;++root){
            if(!dfn[root]){
                ++cnt;
                tarjan(root);
            }
        }
        cout<<ans+cnt-1<<'\n';
    }

}
复制代码

3.二分图

给定一个 N 行 N 列的棋盘,已知某些格子禁止放置。

求最多能往棋盘上放多少块的长度为 2、宽度为 1 的骨牌,骨牌的边界与格线重合(骨牌占用两个格子),并且任意两张骨牌都不重叠。

复制代码
#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> PII;
#define x first
#define y second
const int N = 105;
PII match[N][N];
bool g[N][N],st[N][N];
int n,m,dx[]={1,-1,0,0},dy[]={0,0,1,-1};
bool find(int x,int y){
    for(int i = 0;i<4;++i){
        int a=dx[i]+x,b=dy[i]+y;
        if(a<1||a>n||b<1||b>n||g[a][b]||st[a][b])continue;
        auto t = match[a][b];
        st[a][b] = true;
        if(!t.x || find(t.x,t.y)){
            match[a][b] = {x,y};
            return true;
        }
    }
    return false;
}
int main(){
    int res = 0;
    cin>>n>>m;
    for(int i = 1;i<=m;++i){
        int a,b;
        cin>>a>>b;
        g[a][b] = true;
    }
    for(int i = 1;i<=n;++i){
        for(int j = 1;j<=n;++j){
            if((i+j)%2 && !g[i][j]){
                if(find(i,j)){
                    memset(st,0,sizeof st);
                    ++res;
                }
            }
        }
    }
    cout<<res<<'\n';
    return 0;
    
}
复制代码

4.欧拉回路,路径

给定一张图,请你找出欧拉回路,即在图中找一个环使得每条边都在环上出现恰好一次。
第一行包含一个整数 t,t∈{1,2},如果 t=1,表示所给图为无向图,如果 t=2,表示所给图为有向图。

第二行包含两个整数 n,m,表示图的结点数和边数。

接下来 m 行中,第 i 行两个整数 vi,ui,表示第 i 条边(从 1 开始编号)。

如果 t=1 则表示 vi 到 ui 有一条无向边。
如果 t=2 则表示 vi 到 ui 有一条有向边。
图中可能有重边也可能有自环。

点的编号从 1 到 n。

复制代码
#include<bits/stdc++.h>
using namespace std;

const int N = 1e5 + 10,M = 4e5 + 10;
int din[N],dout[N],cnt,ans[M];
int type,n,m;
int h[N],e[M],id[M],ne[M],idx,used[M];
void add(int a,int b,int i){
    e[idx] = b,id[idx] = i,ne[idx] = h[a],h[a] = idx++;
}
void dfs(int u){
    for(int &i = h[u];~i;){
        int j = e[i];
        if(used[i]){
            i = ne[i];
            continue;
        }
        if(type == 1){
            used[i^1] = true;
        }
        int t = id[i];
        i = ne[i];
        dfs(j);
        ans[++cnt] = t;
    }
}
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    memset(h,-1,sizeof h);
    cin>>type>>n>>m;
    for(int i = 1;i<=m;++i){
        int a,b;
        cin>>a>>b;
        din[b]++;
        dout[a]++;
        add(a,b,i);
        if(type == 1)
        add(b,a,-i);
    }
    if(type == 1){
        for(int i = 1;i<=n;++i){
            if((din[i]+dout[i])&1){
                cout<<"NO"<<'\n';
                return 0;
            }
        }
    }
    else{
        for(int i = 1;i<=n;++i){
            if(din[i] != dout[i]){
                cout<<"NO"<<'\n';
                return 0;
            }
        }
    }
    for(int i = 1;i<=n;++i){
        if(h[i] != -1){
            dfs(i);
            break;
        }
    }
    if(cnt != m){
        cout<<"NO"<<'\n';
    }
    else{
        cout<<"YES"<<'\n';
        for(int i = cnt;i>=1;--i){
            cout<<ans[i]<<" ";
        }
    }
    
    
    return 0;
}
复制代码

四、数据结构

1、主席树

—静态区间第 kk 小

复制代码
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#include<bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10;
struct node{
    int sum,l,r;
}tree[N*60];
int root[N],a[N],sz = 0;
vector<int> v;
int get_id(int x){
    return lower_bound(v.begin(),v.end(),x)  - v.begin() + 1;
}
void update(int l,int r,int &x,int y,int pos){
    x = ++sz;
    tree[x] = tree[y];
    tree[x].sum++;
    if(l==r)return ;
    int m = (l+r)>>1;
    if(pos<=m)update(l,m,tree[x].l,tree[y].l,pos);
    else update(m+1,r,tree[x].r,tree[y].r,pos);
}
int query(int l,int r,int x,int y,int pos){
    if(l==r)return l;
    int sum = tree[tree[y].l].sum - tree[tree[x].l].sum;
    int m = (l+r)>>1;
    if(sum>=pos)return query(l,m,tree[x].l,tree[y].l,pos);
    else return query(m+1,r,tree[x].r,tree[y].r,pos - sum);
}
int main(){
    IOS;
    //freopen("a.txt","r",stdin);
    int n,m;
    cin>>n>>m;
    for(int i = 1 ;i<=n;++i){
        cin>>a[i];
        v.push_back(a[i]);
    }
    sort(v.begin(),v.end());
    v.erase(unique(v.begin(),v.end()),v.end());
    for(int i = 1;i<=n;++i){
        update(1,n,root[i],root[i-1],get_id(a[i]));
    }
    for(int i = 1;i<=m;++i){
        int x,y,k;
        cin>>x>>y>>k;
        cout<<v[query(1,n,root[x-1],root[y],k)-1]<<endl;
    }
    return 0;
} 
复制代码

 

posted @   wanghai673  阅读(38)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· winform 绘制太阳,地球,月球 运作规律
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
点击右上角即可分享
微信分享提示