常用模板(十分不全)

模板

常用技巧

快读(慢写)

#include<iostream>
using namespace std;

int read(){
    char ch=getchar();
    int res=0;
    while(!isdigit(ch)) ch=getchar();
    while(isdigit(ch)) res=(res<<1)+(res<<3)+ch-48,ch=getchar();
    return res;
}

void print(int x){
    if(x/10) print(x/10);
    putchar(x%10+'0');
}

int main(){
    int n;
    n=read();
    print(n);
}

离散化

#include<iostream>
#include<algorithm>
using namespace std;

const int N=1e5+10;

int a[N],b[N];

int main(){
    int n;
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>a[i];
        b[i]=a[i];
    }
    sort(b+1,b+1+n);
    int newn=unique(b+1,b+1+n)-(b+1);
    for(int i=1;i<=n;i++){
        a[i]=lower_bound(b+1,b+1+newn,a[i])-b;
    }
    for(int i=1;i<=n;i++){
        cout<<a[i]<<" ";
    }
}

图论部分

欧拉回路

#include<iostream>
#include<cstdio>
using namespace std;
int A[501][501];
int n;
int B[501];
void dfs(int i){
    printf("%d\n",i);
    for(int j=1;j<=500;j++){
        if(A[i][j]>=1){
            A[i][j]--;
            A[j][i]--;
            dfs(j);
        }
    }
}

int main(){
    int a,b,start=1;
    cin>>n;
    for(int i=1;i<=n;i++){
        scanf("%d%d",&a,&b);
        A[a][b]+=1;
        A[b][a]+=1;
        B[a]++;
        B[b]++;
    }
    for(int i=1;i<=500;i++){
        if(B[i]%2==1) {
            start=i;
            break;
        }
    }
    dfs(start);
}

最短路

floyd

码风突变,因为是一本通粘的

#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
using namespace std;
int a[101][3];
double f[101][101];
int n,i,j,k,x,y,m,s,e;
int main()
{
    cin >> n;
    for (i = 1; i <= n; i++)
        cin >> a[i][1] >> a[i][2];
    cin >> m;
    memset(f,0x7f,sizeof(f));               //初始化f数组为最大值
    
    for (i = 1; i <= m; i++)        //预处理出x、y间距离
    {
        cin >> x >> y;
        f[y][x] = f[x][y] = sqrt(pow(double(a[x][1]-a[y][1]),2) +pow(double(a[x][2]-a[y][2]),2));
            //pow(x,y)表示x^y,其中x,y必须为double类型,要用cmath库
    }
    cin >> s >> e;
    for (k = 1; k <= n; k++)        //floyed 最短路算法
      for (i = 1; i <= n; i++)
        for (j = 1; j <= n; j++)
          if ((i!=j) && (i!=k) && (j!=k) && (f[i][k]+f[k][j]<f[i][j]))
              f[i][j] = f[i][k] + f[k][j];
    printf("%.2lf\n",f[s][e]);
    return 0;
}

spfa

#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;
int n,m;
struct Node{
    int next,to,w;
}edge[100001];
int head[1001],cnt,dis[1001],c[100001][4];
bool vis[1001];

void Add(int u,int v,int w){
    edge[++cnt].next=head[u];
    edge[cnt].to=v;
    edge[cnt].w=w;
    head[u]=cnt;
}

void spfa(int x){
    memset(dis,0x3f,sizeof(dis));
    queue <int> que;
    que.push(x);
    vis[x]=1;
    dis[x]=0;
    while(!que.empty()){
        int k=que.front();
        que.pop();
        vis[k]=0;
        
        for(int i=head[k];i!=0;i=edge[i].next){
            int j=edge[i].to;
            if(dis[j]>dis[k]+edge[i].w){
                dis[j]=dis[k]+edge[i].w;
                if(!vis[j]){
                    vis[j]=1;
                    que.push(j);
                }
            }
        }
    }
}

//void dij(int x)

int main(){
    int h,x,y,z;
    scanf("%d%d%d",&n,&m,&h);
    for(int i=1;i<=m;i++){
        scanf("%d%d%d",&x,&y,&z);
        Add(x,y,z);
        c[i][1]=x;
        c[i][2]=y;
        c[i][3]=z;
    }
    spfa(h);
    
    int k[n+1];
    for(int i=1;i<=n;i++){
        k[i]=dis[i];
    }
    memset(head,0,sizeof(head));
    memset(vis,0,sizeof(vis));
    cnt=0;
    for(int i=1;i<=m;i++){
        Add(c[i][2],c[i][1],c[i][3]);
    }
    spfa(h);
    int maxn=0;
    for(int i=1;i<=n;i++){
        if(k[i]+dis[i]>maxn) maxn=k[i]+dis[i];
    }
    printf("%d",maxn);
    
    return 0;
}

dij

#include<bits/stdc++.h>
using namespace std;
int n,m;
double dis[1001],f[1001][1001];
int x[5],y[5];
pair <int,int> g[1001];
bool vis[1001];
void Add1(int i,int j,int a,int b,int w){
    f[b][a]=f[a][b]=sqrt((double)(x[i]-x[j])*(double)(x[i]-x[j])+(double)(y[i]-y[j])*(double)(y[i]-y[j])) * w;
}
void Add2(int x1,int y1,int i,int a,int b,int w){
    f[b][a]=f[a][b]=sqrt((double)(x[i]-x1)*(double)(x[i]-x1)+(double)(y[i]-y1)*(double)(y[i]-y1)) * w;
}

void dij(int x){
    memset(dis,127,sizeof(dis));
    memset(vis,0,sizeof(vis));
    dis[x]=0;
    priority_queue < pair <int,int> > que;
    que.push(make_pair(0,x));
    while(que.size()){
        int k=que.top().second;
        que.pop();
        if(vis[k]) continue;
        vis[k]=1;
        for(int i=1;i<=n*4;i++){
            if(dis[i]>dis[k]+f[k][i]){
                dis[i]=dis[k]+f[k][i];
                que.push(make_pair(-dis[i],i));
            } 
        }
    }
}
int main(){
    int start,end;
    double w,plane;
    scanf("%d",&m);
    for(int k=1;k<=m;k++){
        memset(f,127,sizeof(f));
        scanf("%d%lf%d%d",&n,&plane,&start,&end);
        for(int i=1;i<=n;i++){
            x[4]=0,y[4]=0;
            for(int j=1;j<=3;j++) {
                scanf("%d%d",&x[j],&y[j]);
                
            }
            int k1=0,k2=0,k3=0;
            for(int i1=1;i1<=3;i1++){
                for(int j=i1+1;j<=3;j++){
                    int l=6-i1-j;
                    if(abs((y[i1]-y[l])*(y[j]-y[l]))==abs((x[i1]-x[l])*(x[j]-x[l]))){
                        k1=i1,k2=j,k3=l;
                    }
                }
            }
            x[4]=x[k1]+x[k2]-x[k3];
            y[4]=y[k1]+y[k2]-y[k3];
            for(int j=1;j<=4;j++)
                for(int h=1;h<=i*4-4;h++){
                        Add2(g[h].first,g[h].second,j,i*4-4+j,h,plane);
                }
            scanf("%lf",&w);
            for(int j=1;j<=4;j++){
                g[i*4-4+j]=make_pair(x[j],y[j]);
                for(int l=j+1;l<=4;l++){
                    Add1(j,l,4*i-4+j,4*i-4+l,w);
                }
            }
        }
        double minl=0x7f7f7f7f;
        for(int i=1;i<=4;i++){
            dij(4*start+i-4);
            for(int j=1;j<=4;j++){
                    minl=min(minl,dis[4*end-4+j]);
            }
        }
        printf("%.1lf\n",minl);
    }
    return 0;
}

并查集

#include<iostream>
using namespace std;
int f[20001];
inline int read(){
    int x=0,f=1;
    char ch=getchar();
    while(!isdigit(ch)){
        f=ch!='-';
        ch=getchar();
    }
    while(isdigit(ch)){
        x=(x<<1)+(x<<3)+(ch^48);
        ch=getchar();
    }
    return f?x:-x;
}
int find(int x){
    while(f[x]!=x) x=f[x];
    return x;
}
int main(){
    int n,m;
    n=read();
    m=read();
    int x,y;
    for(int i=1;i<=n;i++) f[i]=i;
    for(int i=1;i<=m;i++){
        x=read();
        y=read();
        x=find(x);
        y=find(y);
        if(x!=y) f[y]=x;
    }
    n=read();
    for(int i=1;i<=n;i++){
        x=read();
        y=read();
        if(find(x)==find(y)) cout<<"Yes"<<endl;
        else cout<<"No"<<endl;
    }
    return 0;
}

权值并查集

#include<iostream>
#include<algorithm>
#include<cstdio>
using namespace std;
int f[50001],g[50001]/*Óëֱϵ¸¸ÇפιØϵ(½üºõµÈ¼ÛÓë¸ù......)*/;
int find(int x){
    int fa=f[x];
    if(x!=fa){
        f[x]=find(fa);
        g[x]=(g[x]+g[fa])%3;
        return f[x];
    }
    else return fa;
} 
int main(){
    for(int i=1;i<=50000;i++) f[i]=i;
    int n,x,y,z,sum=0,k;
    cin>>n>>k;
    for(int i=1;i<=k;i++){
        cin>>z>>x>>y;
        if(x>n||y>n){
            sum++;
            continue;
        }
        int xx=find(x),yy=find(y);
        if(z==1){
            if(xx==yy&&g[x]!=g[y]){
                sum++;
                continue;
            }
            else if(xx!=yy){
                f[xx]=yy;
                g[xx]=(g[y]-g[x]+3)%3;
            }
        }
        if(z==2){
            if(x==y){
                sum++;
                continue;
            }
            int l=(g[x]-g[y]+3)%3;
            if(l!=1&&xx==yy){
                sum++;
                continue;
            }
            else if(xx!=yy){
                f[xx]=yy;
                g[xx]=(1+g[y]-g[x]+3)%3;
            }
        }
    }
    cout<<sum<<endl;
}

种类并查集

#include<iostream>
#include<algorithm>
#include<cstdio>
using namespace std;
int f[200000],n;
int find(int x){
    if(f[x]!=x){
        x=find(f[x]);
    }
    return f[x];
}

void add(int x,int y){
    int xx=find(x);
    int yy=find(y);
    f[yy]=xx;
}

int main(){
    int sum=0,k,x,y,z;
    cin>>n>>k;
    for(int i=0;i<200000;i++){
        f[i]=i;
    }
    for(int i=1;i<=k;i++){
        scanf("%d%d%d",&z,&x,&y);
        if(x>n||y>n){
            sum++;
            continue;
        }
        if(z==1){
            if(x==y) continue;
            if(find(x)==find(y+2*n)||find(y)==find(x+2*n)){
                sum++;
                continue;
            }
            add(x,y);//同
            add(x+n,y+n);
            add(x+2*n,y+2*n); 
        }
        if(z==2){
            if(x==y){
                sum++;
                continue;
            }
            if(find(n+x)==find(y)||find(x)==find(y)){
                sum++;
                continue;
            }
            add(x,n+y);
            add(2*n+x,y);
            add(x+n,y+2*n);
        }
    }
    cout<<sum;
}

最小生成树

prim

#include<iostream>
#include<cstring>
using namespace std;
int n,m;
int main(){
    int l,y,z,s=0;
    cin>>n>>m;
    int v[n+1][n+1];
    memset(v,0x3f,sizeof(v));
    for(int i=1;i<=m;i++){
        cin>>l>>y>>z;
        v[l][y]=z;
        v[y][l]=z;
        s+=z;
    } 
    int x=1;
    int dis[n+1],sum=0;
    for(int i=1;i<=n;i++) dis[i]=v[i][x];
    dis[x]=0;
    for(int k=1;k<=n-1;k++){
        int min=0x7f7f7f7f,g=0;
        for(int i=1;i<=n;i++){
            if(dis[i] && dis[i]<min){
                min=dis[i];
                g=i;
            }
        }
        sum+=dis[g];
        dis[g]=0;
        for(int i=1;i<=n;i++){
            if(dis[i]>v[i][g]) dis[i]=v[i][g];
        }
    }
    cout<<s-sum;
    return 0;
}

kruskal

#include<iostream>
#include<algorithm>
using namespace std;
int cnt=0,sum=0,f[2001],n,cn=1;
struct Node{
    int from,to,w;
    bool operator < (const Node &A) const {
        return w < A.w;
    }
}edge[10001];

void Add(int x,int y,int z){
    edge[++cnt].from=x;
    edge[cnt].to=y;
    edge[cnt].w=z;
}

int find(int x){
    if(f[x]!=x) f[x]=find(f[x]);
    return f[x];
}

void kruskal(){
    int k=1;
    while(cn<=n-1){
        int x=find(edge[k].from);
        int y=find(edge[k].to);
        if(x!=y){
            f[x]=y;
            sum+=edge[k].w;
            cn++;
        }
        
        k++;
    }
}

int main(){
    int m,x,y,z,sum1=0,k;
    cin>>n>>m;
    for(int i=1;i<=2000;i++) f[i]=i;
    for(int i=1;i<=m;i++){
        cin>>k>>x>>y>>z;
        if(k==1){
            int xx=find(x);
            int yy=find(y);
            if(xx!=yy){
                f[xx]=yy;
                cn++;
            }
            sum+=z;
        }
        Add(x,y,z);
    }
    sort(edge+1,edge+1+cnt);
    
    kruskal();
    
    cout<<sum;
    
}

拓扑排序

#include<iostream>
using namespace std;
#define N 1001
struct Node{
    int to,next,w;
}edge[20001];
int head[N],cnt=0,n,m,r[N],l[N],c[N],U[N],C[N];
bool Technology[N];

void add(int x,int y,int z){
    edge[++cnt].next = head[x];
    edge[cnt].to = y;
    edge[cnt].w = z;
    head[x]=cnt;
    r[y]++;
    c[x]++;
}

void nao(){
    for(int i=1,cn;i<=n;i++){
        cn=0;
        bool a=false;
        for(int j=1;j<=n;j++)
            if(r[j]==0){
                r[j]=100000;
                a=true;
                l[++cn]=j;
            }
        for(int j=1;j<=cn;j++)
            for(int g=head[l[j]];g;g=edge[g].next) {
                r[edge[g].to]--;
                if(C[l[j]]>0){
                    if(!Technology[edge[g].to]) C[edge[g].to]-=U[edge[g].to];
                    C[edge[g].to]+=edge[g].w*C[l[j]];
                    Technology[edge[g].to]=1;
                }
            }
        
    }
}

int main(){
    int x,y,z;
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        cin>>C[i]>>U[i];
    }
    for(int i=1;i<=m;i++){
        cin>>x>>y>>z;
        add(x,y,z);
    }
    nao();
    bool h=0;
    for(int i=1;i<=n;i++){
        if(c[i]==0){
            if(C[i]>0){
                cout<<i<<" "<<C[i]<<endl;
                h=1;
            }
        }
    }
    if(!h) cout<<"NULL";
    
    return 0;
}

差分约束

#include<iostream>
#include<cstring>
using namespace std; 
const int M=1e7+10,N=1e5+10;
struct Node{
    int next,to,w;
}e[M];
bool vis[N];
int dis[N],head[N],cnt,n,m;

void add(int u,int v,int w){
    e[++cnt].next=head[u];
    e[cnt].to=v;
    e[cnt].w=w;
    head[u]=cnt;
}

void spfa(int x){
    vis[x]=1;
    for(int i=head[x];i;i=e[i].next){
        if(dis[e[i].to]<dis[x]+e[i].w){
            dis[e[i].to]=dis[x]+e[i].w;
            if(vis[e[i].to]) {
                printf("No");
                exit(0);
            }
            spfa(e[i].to);
            
        }
    }
    vis[x]=0;
}

int main(){
    cin>>n>>m;
    int x,y,z,w;
    for(int i=1;i<=m;i++){
        cin>>z;
        if(z==1){
            cin>>x>>y>>w;
            add(y,x,-w);
        }
        if(z==2){
            cin>>x>>y>>w;
            add(x,y,w);
        }
        if(z==3){
            cin>>x>>y;
            add(x,y,0);
            add(y,x,0);
        }
    }
    for(int i=1;i<=n;i++) add(0,i,0);
    memset(dis,-0x3f,sizeof(dis));
    dis[0]=0;
    spfa(0);
    cout<<"Yes";
    return 0;
}

tarjan

1. 强连通分量

#include<iostream>
#include<stack>
using namespace std;
const int N=1e6+10;
int cnt,head[N],num,dfn[N],low[N],t,Num[N];
bool vis[N];
struct Node{
    int nxt,to;
}e[N];

void Add(int u,int v){
    e[++cnt]={head[u],v};
    head[u]=cnt;
}

stack <int> sta;
void tarjan(int x){
    dfn[x]=low[x]=++num;
    sta.push(x);
    vis[x]=1;
    for(int i=head[x];i;i=e[i].nxt){
        int to=e[i].to;
        if(!dfn[to]){
            tarjan(to);
            low[x]=min(low[x],low[to]);
        } 
        else if(vis[to]) low[x]=min(low[x],dfn[to]);
    }
    if(dfn[x]==low[x]){
        t++;
        int y;
        do{
            y=sta.top();
            sta.pop();
            vis[y]=0;
            Num[t]++;
        }while(x!=y);
    }
}

int main(){
    int n,x;
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>x;
        Add(i,x);
        Add(0,i);
    }
    tarjan(0);
    int minl=0x3f3f3f3f;
    for(int i=1;i<=t;i++){
        if(Num[i]>=2) minl=min(minl,Num[i]);
    }
    cout<<minl;
}

2. 求割点

#include<iostream>
using namespace std;
const int N=1e5+1;
int p[N],head[N],cnt,root,step,dfn[N],low[N];
bool cut[N];

struct Node{
    int nxt,to;
}e[N];

void add(int x,int y){
    e[++cnt]={head[x],y};
    head[x]=cnt;
}

void tarjan(int x,int fa){
    dfn[x]=low[x]=++step;
    int son=0;
    for(int i=head[x];i;i=e[i].nxt){
        int to=e[i].to;
        if(!dfn[to]){
            son++;
            tarjan(to,x);
            low[x]=min(low[x],low[to]);
            if(low[to]>=dfn[x]){
                if(x!=fa || son>1) cut[x]=1;
            }
        }
        else low[x]=min(low[x],dfn[to]);
    }
}

int main(){
    int n,x,y;
    cin>>n;
    while(cin>>x){
        cin>>y;
        add(x,y);
        add(y,x);
    }
    for(int i=1;i<=n;i++){
        if(!dfn[i]) {
            tarjan(i,i);
        }
    }
    
    int sum=0;
    for(int i=1;i<=n;i++){
        if(cut[i]){
            sum++;
        }
    }
    cout<<sum<<endl;
    for(int i=1;i<=n;i++) if(cut[i]) cout<<i<<endl;
}

3. 求桥(割边)

#include<iostream>
#include<cstring>
using namespace std;
const int N=1e6+100;
int head[N],low[N],dfn[N],p[N],cnt,step;
bool g[N];

struct Node{
    int nxt,to,id;
}e[N];

void add(int x,int y,int z){
    e[++cnt]={head[x],y,z};
    head[x]=cnt;
}

void tarjan(int x){
    dfn[x]=low[x]=++step;
    for(int i=head[x];i;i=e[i].nxt){
        int to=e[i].to;
        if(!dfn[to]){
            p[to]=e[i].id;
            tarjan(to);
            low[x]=min(low[x],low[to]);
        }
        else if(e[i].id!=p[x]) low[x]=min(low[x],dfn[to]);
    }
    if(p[x] && dfn[x]==low[x]) g[p[x]]=1;
}

int main(){
    int n;
    while(cin>>n){
        memset(g,0,sizeof(g));
        memset(low,0,sizeof(low));
        memset(dfn,0,sizeof(dfn));
        memset(e,0,sizeof(e));
        memset(head,0,sizeof(head));
        cnt=0;
        int m,qwq=0;
        cin>>m;
        if(n==0) continue;
        for(int i=1;i<=m;i++){
            int x,y;
            cin>>x>>y;
            qwq++;
            add(x,y,qwq);
            add(y,x,qwq);
        }
        for(int i=1;i<=n;i++){
            if(!dfn[i]) tarjan(i);
        }
        int sum=0;
        for(int i=1;i<=cnt;i++){
                if(g[e[i].id]) {
                g[e[i].id]=0;
                sum++;
            }
        }
        cout<<sum<<endl;
    }
}

倍增LCA

#include<iostream>
#include<cmath>
using namespace std;
int dp[1001][101],deep[1001],cnt,head[1001],n;

struct Node{
    int nxt,to;
}e[114514];

void add(int x,int y){
    e[++cnt]={head[x],y};
    head[x]=cnt;
}

void dfs(int x,int fa){
    deep[x]=deep[fa]+1;
    dp[x][0]=fa;
    for(int j=1;(1<<j)<=deep[x];j++){
        dp[x][j]=dp[dp[x][j-1]][j-1];
    }
    for(int i=head[x];i;i=e[i].nxt){
        int to=e[i].to;
        if(to!=fa) dfs(to,x);
    }
}

int lca(int u,int v){
    int deepu=deep[u],deepv=deep[v];
    if(deepu!=deepv){
        if(deepu<deepv){
            swap(deepu,deepv);
            swap(u,v);
        }
        int d=deepu-deepv;
        for(int i=0;i<=log2(n)+1;i++){
            if((1<<i)&d) u=dp[u][i];
        }
    }
    if(u==v) return u;
    for(int i=log2(n)+1;i>=0;i--){
        if(deep[dp[u][i]]<=0) continue;
        if(dp[u][i]==dp[v][i]) continue;
        else v=dp[v][i],u=dp[u][i];
    }
    return dp[u][0];
}

int main(){
    cin>>n;
    for(int i=1;i<=n;i++){
        int x,y;
        cin>>x>>y;
        add(x,y);
        add(y,x);
    }
    int x,y;
    cin>>x>>y;
    dfs(1,1);
    cout<<lca(x,y);
}

二分图匹配

#include<iostream>
using namespace std;
int col[100001],cnt,head[100001];

struct Star{
    int nxt,to;
}e[1000001];

void add(int u,int v){
    e[++cnt]={head[u],v};
    head[u]=cnt;
}

bool dfs(int x,int fa,int color){
    col[x]=color;
    for(int i=head[x];i;i=e[i].nxt){
        int to=e[i].to;
        if(to==fa) continue;
        if(col[to]==0 && (!dfs(to,x,3-color))) return false;//如果未染色,但染色失败,返回false
        if(col[to]==color) return false;//如果染色,但颜色相同,这说明相同颜色相通,不符合定义
    }
    return true;
}

int main(){
    ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
    int n,m;
    bool flag=true;
    cin>>n>>m;
    for(int i=1;i<=m;i++){
        int x,y;
        cin>>x>>y;
        add(x,y);add(y,x);
    }
    for(int i=1;i<=n;i++){//用于处理不联通的情况
        if(!col[i]){
            if(!dfs(i,0,1)){
                flag=false;
                break;
            }
        }
    }
    if(flag) cout<<"Yes";
    else cout<<"No";
}

匈牙利算法

#include<iostream>
#include<cstring>
using namespace std;

int cnt,head[100001],match[100001]/*右方点的匹配*/;
int n_le/*左边的点数*/,n_ri/*右边的点数*/,m;
bool vis[100001];//右方点是否匹配

struct Star{
    int nxt,to;
}e[1000001];

void add(int u,int v){
    e[++cnt]={head[u],v};
    head[u]=cnt;
}

bool Match(int x){
    for(int i=head[x];i;i=e[i].nxt){
        int to=e[i].to;
        if(!vis[to]){
            vis[to]=true;
            if((!match[to]) || Match(match[to])){
                match[to]=x;//改嫁(换色)
                return true;
            }
        }
    }
    return false;
}

int Hungarian(){
    int ans_Hungarian=0;
    for(int i=1;i<=n_le;i++){
        memset(vis,0,sizeof(vis));
        if(Match(i)){
            ans_Hungarian++;
        }
    }
    return ans_Hungarian;
}

int main(){
    ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
    cin>>n_le>>n_ri>>m;
    for(int i=1;i<=m;i++){
        int x,y;
        cin>>x>>y;
        add(x,y);add(y,x);
    }
    cout<<Hungarian();
}

树相关

重链剖分

#include<bits/stdc++.h>
using namespace std;
#define lid id<<1
#define rid id<<1|1
// #define int long long
const int N=1e6+10;
int timer,head[N],cnt;
int son[N],dfn[N],deep[N],siz[N],f[N],top[N],cnin[N],a[N];

struct Star{
    int nxt,to;
}e[N];

struct Tree{
    int l,r,maxn,sum,lazy;
}d[4*N];

void PushUp(int id){
    d[id].sum=d[lid].sum+d[rid].sum;
    d[id].maxn=max(d[lid].maxn,d[rid].maxn);
}

void Build(int id,int l,int r){
    d[id].l=l;
    d[id].r=r;
    if(l==r){
        d[id].sum=a[l];
        d[id].maxn=a[l];
        return;
    }
    int mid=(l+r)>>1;
    Build(lid,l,mid);
    Build(rid,mid+1,r);
    PushUp(id);
}

void Update(int id,int pos,int w){
    if(d[id].l==d[id].r){
        d[id].sum=w;
        d[id].maxn=w;
        return;
    }
    if(pos<=d[lid].r) Update(lid,pos,w);
    else Update(rid,pos,w);
    PushUp(id);
}

int Get_Sum(int id,int l,int r){
    if(l<=d[id].l && d[id].r<=r) return d[id].sum;
    int sum=0;
    if(l<=d[lid].r) sum=Get_Sum(lid,l,r);
    if(r>d[lid].r) sum+=Get_Sum(rid,l,r);
    return sum;
}

int Get_Max(int id,int l,int r){
    if(l<=d[id].l && d[id].r<=r) return d[id].maxn;
    int maxn=-INT_MAX;
    if(l<=d[lid].r) maxn=Get_Max(lid,l,r);
    if(r>d[lid].r) maxn=max(maxn,Get_Max(rid,l,r));
    return maxn;
}

void add(int u,int v){
    e[++cnt]={head[u],v};
    head[u]=cnt;
}

void dfs1(int x,int fa){//初始化size,father,deep,son
    siz[x]=1;
    f[x]=fa;
    deep[x]=deep[fa]+1;
    int max_size=0;
    for(int i=head[x];i;i=e[i].nxt){
        int to=e[i].to;
        if(deep[to]) continue;
        dfs1(to,x);
        siz[x]+=siz[to];
        if(siz[to]>max_size){
            max_size=siz[to];
            son[x]=to;
        }
    }
}

void dfs2(int x,int fa){//维护dfn,top,rak
    dfn[x]=++timer;
    top[x]=fa;
    a[dfn[x]]=cnin[x];
    if(son[x]){
        dfs2(son[x],fa);
    }
    for(int i=head[x];i;i=e[i].nxt){
        int to=e[i].to;
        if((to==son[x]) || (to==f[x])) continue;
        dfs2(to,to);
    }
}

int Query_Sum(int x,int y){
    int sum=0;
    while(top[x]!=top[y]){
        if(deep[top[x]]<deep[top[y]]) swap(x,y);
        sum+=Get_Sum(1,dfn[top[x]],dfn[x]);
        x=f[top[x]];
    }
    if(deep[x]>deep[y]) swap(x,y);
    sum+=Get_Sum(1,dfn[x],dfn[y]);
    return sum;
}

int Query_Max(int x,int y){
    int maxn=-INT_MAX;
    while(top[x]!=top[y]){
        if(deep[top[x]]<deep[top[y]]) swap(x,y);
        maxn=max(maxn,Get_Max(1,dfn[top[x]],dfn[x]));
        x=f[top[x]];
    }
    if(deep[x]>deep[y]) swap(x,y);
    maxn=max(maxn,Get_Max(1,dfn[x],dfn[y]));
    return maxn;
}

signed main(){
    ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
    int n,m;
    cin>>n;
    for(int i=1;i<n;i++){
        int x,y;
        cin>>x>>y;
        add(x,y);
        add(y,x);
    }
    for(int i=1;i<=n;i++) cin>>cnin[i];
    dfs1(1,0);
    dfs2(1,1);
    Build(1,1,timer);
    cin>>m;
    for(int i=1;i<=m;i++){
        string op;
        int x,y;
        cin>>op>>x>>y;
        if(op=="QMAX"){
            cout<<Query_Max(x,y)<<"\n";
        }
        if(op=="QSUM"){
            cout<<Query_Sum(x,y)<<"\n";
        }
        if(op=="CHANGE"){
            Update(1,dfn[x],y);
        }
    }
}

虚树

// 双排序维护
#include<bits/stdc++.h>
using namespace std;
#define re register
#define int long long
#define endl '\n'
const int N=6e5+10;

inline int max(int x,int y){return (x<y)?y:x;}
inline int min(int x,int y){return (x<y)?x:y;}

struct Node{
	int nxt,to,w;
}e[N];

int head[N],cntt;

int f[N][31],mindis[N][31],dep[N],dfn[N],timer;

void add(int x,int y,int w){
	e[++cntt]={head[x],y,w};
	head[x]=cntt;
}

void dfs(int x,int fa){
	for(int i=1;i<=30;i++){
		mindis[x][i]=0x3f3f3f3f3f3f3f3f;
	}
	dep[x]=dep[fa]+1;
	f[x][0]=fa;
	dfn[x]=++timer;
	for(int i=1;i<=30;i++){
		f[x][i]=f[f[x][i-1]][i-1];
		mindis[x][i]=min(mindis[x][i-1],mindis[f[x][i-1]][i-1]);
	}
	for(int i=head[x];i;i=e[i].nxt){
		int to=e[i].to;
		if(to==fa) continue;
		mindis[to][0]=e[i].w;
		dfs(to,x);
	}
	head[x]=0;
}

int dis;

int Lca(int u,int v){
	dis=0x3f3f3f3f3f3f3f3f;
	if(dep[u]!=dep[v]){
		int deepu=dep[u],deepv=dep[v];
		if(deepu<deepv){
			swap(u,v);
			swap(deepu,deepv);
		}
		int d=deepu-deepv;
		for(int i=0;i<=20;i++){
			if(d&(1<<i)){
				dis=min(dis,mindis[u][i]);
				u=f[u][i];
			}
		}
	}
	if(u==v) return u;
	for(int i=20;i>=0;i--){
		if(dep[u]<=0) continue;
		if(f[u][i]!=f[v][i]){
			dis=min(dis,min(mindis[u][i],mindis[v][i]));
			u=f[u][i],v=f[v][i];
		}
	}
	dis=min(dis,min(mindis[u][0],mindis[v][0]));
	return f[u][0];
}

int dp[N];
bool import[N];

void dfs_ans(int x){
	for(int i=head[x];i;i=e[i].nxt){
		int to=e[i].to,w=e[i].w;
		if(to==f[x][0]) continue;
		dfs_ans(to);
		if(import[to]) dp[x]+=w;
		else dp[x]+=min(dp[to],w);
	}
}

void dfs_cut(int x){
	for(auto i=head[x];i;i=e[i].nxt){
		int to=e[i].to;
		if(to==f[x][0]) continue;
		dfs_cut(to);
	}
	head[x]=0;
	dp[x]=0;
}

int point[N];

bool cmp(int a,int b){
	return dfn[a]<dfn[b];
}

int a[N];

void Build(int cnt){
	cntt=0;
	int len=0;
	sort(point+1,point+1+cnt,cmp);
	for(int i=1;i<cnt;i++){
		a[++len]=point[i];
		a[++len]=Lca(point[i],point[i+1]);
//		cerr<<point[i]<<'&'<<point[i+1]<<" : "<<Lca(point[i],point[i+1])<<"qwq\n";
	}
	a[++len]=point[cnt];
	sort(a+1,a+1+len,cmp);
	len=unique(a+1,a+1+len)-a-1;
	for(int i=1,lca;i<len;i++){
		lca=Lca(a[i],a[i+1]);
		Lca(lca,a[i+1]);
		add(lca,a[i+1],dis);
//		cerr<<a[i]<<" & "<<a[i+1]<<"->"<<lca<<" : "<<dis<<"awa\n";
	}
}

signed main()
{
	ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
	int n;
	cin>>n;
	int x,y,z;
	for(int i=1;i<n;i++){
		cin>>x>>y>>z;
		add(x,y,z);
		add(y,x,z);
	}
	dfs(1,0);
	int m,k,h;
	cin>>m;
	for(int i=1;i<=m;i++){
		cin>>k;
		for(int j=1;j<=k;j++){
			cin>>h;
			point[j]=h;
			import[h]=1;
		}
		point[++k]=1;
		Build(k);
//		cerr<<head[1]<<'.';
		dfs_ans(1);
		cout<<dp[1]<<'\n';
		for(int j=1;j<=k;j++){
			import[point[j]]=0;
		}
		dfs_cut(1);
	}
	return 0;
}

数论部分

高斯消元

#include<iostream>
#include<cmath>
#include<cstdio>
double eps=1e-8;
using namespace std;
double a[101][101],ans[101];//Ç°Ò»¸ö´ú±íÐÐ 
int n;

void Goh(){
    for(int i=1;i<=n;i++){
        int r=i;
        for(int j=1;j<=n;j++){
            if(abs(a[j][j])>eps && j<i) continue;
            if(fabs(a[j][i])>fabs(a[r][i]))
                r=j;
        }
            
        if(fabs(a[r][i])<eps){
            continue;
        }
        if(r!=i) swap(a[i],a[r]);
        double div=a[i][i];
        for(int j=i;j<=n+1;j++) a[i][j]/=div;
        for(int j=i+1;j<=n;j++){
            div=a[j][i];
            for(int k=i;k<=n+1;k++){
                a[j][k]-=a[i][k]*div;
            }
        }
    }
    ans[n]=a[n][n+1];
    for(int i=n-1;i>=1;i--){
        ans[i]=a[i][n+1];
        for(int j=n;j>i;j--) ans[i]-=ans[j]*a[i][j],a[i][n+1]-=ans[j]*a[i][j],a[i][j]=0;
    }
    int key=1;
    for(int i=1;i<=n;i++){
        if(fabs(a[i][i])<eps){
            if(fabs(a[i][n+1])>eps) key=-1;
            else if(key!=-1) key=0;
        }
    }
    if(key!=1){
        cout<<key;
        exit(0);
    } 
}

int main(){
    cin>>n;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n+1;j++)
            cin>>a[i][j];
    Goh();
    for(int i=1;i<=n;i++){
        if(fabs(ans[i])<eps) printf("x%d=0\n",i);
        printf("x%d=%.2lf\n",i,ans[i]);
    }
}

欧拉函数

 #include<iostream>
 #include<cmath>
using namespace std;
const int N=1e7+5;
int phi[N],prime[N];
bool not_prime[N];

int eular_phi(int n){
    int m=(int)(sqrt(n));
    int ans=n;
    for(int i=2;i<=m;i++){
        if(n%i==0){
            ans=ans/i*(i-1);
            while(n%i==0) n/=i;
        } 
    }
    if(n>1) ans=ans/n*(n-1);
    return ans;
}

void getEular(int n){
    phi[1]=1;
    for(int i=2;i<=n;i++){
        if(!not_prime[i]){
            prime[++prime[0]]=i;
            phi[i]=i-1;
        }
        for(int j=1;j<=prime[0];j++){
            int k=i* prime[j];
            if(k>n) break;
            not_prime[k]=1;
            if(i%prime[j]==0){
                phi[k]=phi[i]*prime[j];
                break;
            }
            else phi[k]=phi[i]*(prime[j]-1);
        }
    }
}

int main(){
    cout<<"1Ϊ²éѯn¤ÎÅ·À­º¯ÊýÖµ,2Ϊ²éѯ1~n\nÇëÊäÈë:";
    ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
    int op;
    cin>>op;
    int n;
    cin>>n;
    if(op==1){
        cout<<eular_phi(n);
    }
    else{
        getEular(n);
        for(int i=1;i<=n;i++){
            cout<<phi[i]<<'\n';
        }
    }
}

扩欧

#include<iostream>
using namespace std;

int exgcd(int a,int b,int &x,int &y){
    if(b==0){
        x=1;
        y=0;
        return a;
    }
    int res=exgcd(b,a%b,x,y);
    int t=x;
    x=y;
    y=t-a/b*y;
    return res;
}

int main(){
    int a,b,x=0,y=0;
    cin>>a>>b;
    exgcd(a,b,x,y);
    cout<<x<<" "<<y;
 // cout<<(x%b+b)%b;
}

数据结构

树状数组

单点修改,区间查询

#include<iostream>
#include<cstring>
using namespace std;
const int N=5*1e5+100;
int c[N],a[N],n;
int lower_bit(int x){
    return x&(-x);
}

void AddPoint(int x,int w){
    while(x<=n){
        c[x]+=w;
        x+=lower_bit(x);
    }
}

int Sum(int l,int r){
    int sum=0;
    while(r>=l){
        sum+=c[r];
        r-=lower_bit(r);
    }
    return sum;
}

void SumPrint(int l,int r){
    cout<<Sum(1,r)-Sum(1,l-1)<<endl;
}

int main(){
    int m;
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>a[i];
        AddPoint(i,a[i]);
    }
    cin>>m;
    string x;
    int y,z;
    for(int i=1;i<=m;i++){
        cin>>x>>y>>z;
        if(x=="ADD") AddPoint(y,z);
        else SumPrint(y,z);
    }
}

区间修改,区间查询

#include<iostream>
#include<cstring>
using namespace std;
const int N=5*1e5+100;
int c[N],a[N],n,b[N];
int lower_bit(int x){
    return x&(-x);
}

void AddPoint(int x,int w){
    while(x<=n){
        c[x]+=w;
        x+=lower_bit(x);
    }
}

void Add(int l,int r,int w){
    AddPoint(l,w);
    AddPoint(r+1,-w);
}

int Sum(int l,int r){
    int sum=0;
    while(r>=l){
        sum+=c[r];
        r-=lower_bit(r);
    }
    return sum;
}

void SumPrint(int l){
    cout<<Sum(1,l)<<endl;
}

int main(){
    int m;
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>a[i];
        b[i]=a[i]-a[i-1];
        AddPoint(i,b[i]);
    }
    string x;
    int y,z,h;
    cin>>m;
    for(int i=1;i<=m;i++){
        cin>>x;
        if(x=="ADD"){
            cin>>y>>z>>h;
            Add(y,z,h);
        } 
        else {
            cin>>y;
            SumPrint(y);
        }
    }
}

线段树

#include<iostream>
#include<cstring>
#define lid id<<1
#define rid id<<1|1
using namespace std;
int a[100001];
struct Node{
    int l,r,sum,lazy;
}d[500001];

void PushDown(int id){
    if(d[id].lazy){
        d[lid].lazy+=d[id].lazy;
        d[rid].lazy+=d[id].lazy;
        d[lid].sum+=(d[lid].r-d[lid].l+1)*d[id].lazy;
        d[rid].sum+=(d[rid].r-d[rid].l+1)*d[id].lazy;
        d[id].lazy=0;
    }
}

void Build(int id,int l,int r){
    d[id].l=l;
    d[id].r=r;
    if(l==r){
        d[id].sum=a[l];
        return;
    }
    int mid=(l+r)>>2;
    Build(lid,l,mid);
    Build(rid,mid+1,r);
    d[id].sum=d[lid].sum+d[rid].sum;
}

int Sum(int id,int l,int r){
    if(l<=d[id].l && d[id].r<=r) return d[id].sum;
    PushDown(id);
    int sum=0;
    if(l<=d[lid].r) sum+=Sum(lid,l,r);
    if(r>d[lid].r) sum+=Sum(rid,l,r);
    return sum;
}

void Update(int id,int l,int r,int w){
    if(l<=d[id].l && d[id].r<=r){
        d[id].sum+=(d[id].r-d[id].l+1)*w;
        d[id].lazy+=w;
        return;
    }
    PushDown(id);
    if(l<=d[lid].r) Update(lid,l,r,w);
    if(r>d[lid].r) Update(rid,l,r,w);
    d[id].sum=d[lid].sum+d[rid].sum;
}

int main(){
    ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
    int n,m,y,z,g;
    string x;
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>a[i];
    }
    Build(1,1,n);
    cin>>m;
    for(int i=1;i<=m;i++){
        cin>>x;
        if(x=="ADD"){
            cin>>y>>z>>g;
            Update(1,y,z,g);
        }
        else{
            cin>>y>>z;
            cout<<Sum(1,y,z)<<endl;
        }
    }
}

单调队列

#include<cstdio>
int maxn[10000001],minl[10000001],x[10000001];

int main(){
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) scanf("%d",&x[i]);
    int head=0,tail=0;
    for(int i=1;i<m;i++){
        while(head<=tail&&x[minl[tail]]>x[i]) tail--;
        minl[++tail]=i;
    }
    for(int i=m;i<=n;i++){
        while(head<=tail&&x[minl[tail]]>x[i]) tail--;
        minl[++tail]=i;
        while(minl[head]<=i-m) head++;
        printf("%d ",x[minl[head]]);
    }
    printf("\n");

    head=0,tail=0;
    for(int i=1;i<m;i++){
        while(head<=tail&&x[maxn[tail]]<x[i]) tail--;
        maxn[++tail]=i;
    }
    for(int i=m;i<=n;i++){
        while(head<=tail&&x[maxn[tail]]<x[i]) tail--;
        maxn[++tail]=i;
        while(maxn[head]<=i-m) head++;
        printf("%d ",x[maxn[head]]);
    }
}

单调栈

#include<cstdio>
#include<iostream>
#include<stack>
using namespace std;
int x[1000001],houseVal[1000001];
int main(){
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++) cin>>x[i];
    std::stack <int> ad;
    for(int i=1;i<=n+1;i++){
        while((!ad.empty())&&(x[ad.top()]>x[i])){
            houseVal[ad.top()]=i-ad.top();
            ad.pop();
        } 
        ad.push(i);
    }
    for(int i=n;i>=0;i--){
        while((!ad.empty())&&(x[ad.top()]>x[i])){
            houseVal[ad.top()]+=ad.top()-i;
            ad.pop();
        } 
        ad.push(i);
    }
    int maxn=0;
    for(int i=1;i<=n;i++){
        maxn=max(maxn,x[i]*(houseVal[i]-1));
    }
    cout<<maxn;
}

ST表

#include<iostream>
#include<cmath>
using namespace std;
int dp[101][101];

int main(){
    int n;
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>dp[i][0];
    }
    for(int j=1;j<=10;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 x,y,k;
    cin>>x>>y;
    k=log2(y-x+1);
    cout<<max(dp[x][k],dp[y-(1<<k)+1][k]);
}

分块

#include<iostream>
#include<cmath>
using namespace std;
#define int long long
int id[114514],n,a[114514];
struct kuai{
    int sum,l,r,lazy;
}block[114514];

int Sum(int l,int r){
    int ans=0,lid=id[l],rid=id[r],k=0;
    if(lid==rid){
        for(int i=l;i<=r;i++) ans+=(a[i]+block[lid].lazy);//暴力求和 
    }
    else{
        for(int i=l;i<=block[lid].r;i++) ans+=(a[i]+block[lid].lazy);//左散块 
        for(int i=lid+1;i<rid;i++) ans+=block[i].sum,k+=sqrt(n);//中间整块 
        for(int i=block[rid].l;i<=r;i++) ans+=(a[i]+block[rid].lazy);//右散块 
    }
    return ans;
}

void Update(int l,int r,int w){//同上 
    int lid=id[l],rid=id[r];
    if(lid==rid){
        for(int i=l;i<=r;i++) a[i]+=w,block[lid].sum+=w;
    }
    else{
        for(int i=l;i<=block[lid].r;i++) a[i]+=w,block[lid].sum+=w;
        for(int i=lid+1;i<rid;i++) block[i].sum+=(block[i].r-block[i].l+1)*w,block[i].lazy+=w;
        for(int i=block[rid].l;i<=r;i++) a[i]+=w,block[rid].sum+=w;
    }
}

signed main(){
    cin>>n;
    int m;
    cin>>m;
    int sq=sqrt(n)+1;
    for(int i=1;i<=n;i++){
        cin>>a[i];
        id[i]=(i-1)/sq+1;
        block[id[i]].sum+=a[i];
    }
    for(int i=1;i<=n/sq;i++){
        block[i].l=sq*(i-1)+1;
        block[i].r=sq*i;
    }
    if(n%sq!=0){
        block[n/sq+1].l=block[n/sq].r+1;
        block[n/sq+1].r=n;
    }
    for(int i=1;i<=m;i++){
        char op;
        int x,y,z;
        cin>>op>>x>>y;
        if(op=='Q'){
            cout<<Sum(x,y)<<"\n";
        }
        else{
            cin>>z;
            Update(x,y,z);
        }
    }
}

莫队

普通莫队

#include<iostream>
#include<algorithm>
#include<cmath>
#define int long long
using namespace std;
int belong[1145140],cnt[1000001],aa[114514],now,ans[1145140];
struct Q{
    int id,l,r;
}q[1145140];

int read(){//快读
    char ch=getchar();int res=0;
    while(!isdigit(ch)) ch=getchar();
    while(isdigit(ch)) res=(res<<1)+(res<<3)+ch-48,ch=getchar();
    return res;
}

void print(int x){
    if(x/10) print(x/10);
    putchar(x%10+'0');
}

bool cmp(Q a,Q b){//卡常
    return (belong[a.l]^belong[b.l])?(belong[a.l]<belong[b.l]):((belong[a.l]&1)?a.r<b.r:a.r>b.r);
}

inline void del(int x){//卡常时不用它
    if(cnt[aa[x]]==1) now--;
    cnt[aa[x]]--;
}

inline void add(int x){
    if(!cnt[aa[x]]) now++;
    cnt[aa[x]]++;
}

signed main(){
    int n,m;
    cin>>n;
    for(int i=1;i<=n;i++){
        aa[i]=read();
    }
    cin>>m;
    int sq=n/sqrt(m);
    for(int i=1;i<=n;i++){
        belong[i]=(i-1)/sq+1;
    }
    for(int i=1;i<=m;i++){
        q[i].l=read(),q[i].r=read();
        q[i].id=i;
    }
    sort(q+1,q+1+m,cmp);//莫队核心之一
    int l=1,r=0;
    for(int i=1;i<=m;i++){
        int ql=q[i].l,qr=q[i].r;
        while(l<ql) now-=!--cnt[aa[l++]];//卡常
        while(l>ql) now+=!cnt[aa[--l]]++;
        while(r<qr) now+=!cnt[aa[++r]]++;
        while(r>qr) now-=!--cnt[aa[r--]];
        ans[q[i].id]=now;
    }
    for(int i=1;i<=m;i++){
        print(ans[i]);
        putchar('\n');
    }
}

带修莫队

#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
const int N=143333;
int belong[N],a[N],cnt_q,cnt_ch,timer[1000010],now,ans[N];
struct Node{
    int l,r,time,id;
}q[N],ch[N];

inline int read(){
    char ch=getchar();
    int res=0;
    while(!isdigit(ch)) ch=getchar();
    while(isdigit(ch)) res=(res<<1)+(res<<3)+(ch^48),ch=getchar();
    return res;
}

void print(int x){
    if(x/10) print(x/10);
    putchar(x%10+'0');
}

bool cmp(Node a,Node b){
    return (belong[a.l]^belong[b.l])?(belong[a.l]<belong[b.l]):((belong[a.r]^belong[b.r])?(belong[a.r]<belong[b.r]):(a.time<b.time));
}


int main(){
    int n,m;
    n=read(),m=read();
    int sq=pow(n,0.66666);
    for(int i=1;i<=n;i++){
        a[i]=read();
        belong[i]=(i-1)/sq+1;
    }
    for(int i=1;i<=m;i++){
        int x,y;
        char op;
        cin>>op;
        x=read(),y=read();
        if(op=='Q') q[++cnt_q].l=x,q[cnt_q].r=y,q[cnt_q].id=cnt_q,q[cnt_q].time=cnt_ch;
        else ch[++cnt_ch].l=x,ch[cnt_ch].id=cnt_ch,ch[cnt_ch].r=y;
    }
    sort(q+1,q+1+cnt_q,cmp);
    int l=1,r=0,now_time=0;
    for(int i=1;i<=cnt_q;i++){
        int posl=q[i].l,posr=q[i].r,post=q[i].time;
        while(l<posl) now-=!--timer[a[l++]];
        while(l>posl) now+=!timer[a[--l]]++;
        while(r<posr) now+=!timer[a[++r]]++;
        while(r>posr) now-=!--timer[a[r--]];
        while(now_time<post){
            now_time++;
            if(posl<=ch[now_time].l && ch[now_time].l<=posr) now+=(!timer[ch[now_time].r]++)-(!--timer[a[ch[now_time].l]]);
            swap(a[ch[now_time].l],ch[now_time].r);
        }
        while(now_time>post){
            if(posl<=ch[now_time].l && ch[now_time].l<=posr) now+=(!timer[ch[now_time].r]++)-(!--timer[a[ch[now_time].l]]);
            swap(a[ch[now_time].l],ch[now_time].r);
            now_time--;
        }
        ans[q[i].id]=now;
    }
    for(int i=1;i<=cnt_q;i++) print(ans[i]),putchar('\n');
}

回滚莫队

#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstring>
#define int long long
using namespace std;
const int N=1e5+100;
int T[N],en[N],cnt1[N],cnt2[N],a[N],ans[N],belong[N],aa[N],en2[N];

struct Node{
    int l,r,id;
}q[N];

bool cmp(Node a,Node b){
    return (belong[a.l]^belong[b.l])?(belong[a.l]<belong[b.l]):(a.r<b.r);
}

signed main(){
    ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
    int n,m;
    cin>>n>>m;
    int sq=ceil(n/sqrt(m));
    for(int i=1;i<=n;i++){
        cin>>a[i];
        T[i]=a[i];
        aa[i]=a[i];
        belong[i]=(i-1)/sq+1;
        en2[belong[i]]=i;
    }
    for(int i=1;i<=m;i++){
        cin>>q[i].l>>q[i].r;
        q[i].id=i;
    }
    sort(aa+1,aa+1+n);
    int newn=unique(aa+1,aa+1+n)-(aa+1);
    for(int i=1;i<=n;i++){
        a[i]=lower_bound(aa+1,aa+1+newn,a[i])-aa;
    }
    sort(q+1,q+1+m,cmp);
    int qwq=belong[n];
    int l,r,now,tag,j=1;
    for(int i=1;i<=qwq;i++){
        l=en2[i]+1,r=en2[i];
        memset(cnt1,0,sizeof(cnt1));
        now=0,tag=0;
        for(;belong[q[j].l]==i;j++){
            int posl=q[j].l,posr=q[j].r;
            // cerr<<q[j].id<<" "<<posl<<" "<<posr<<"\n";
            tag=0;
            if(belong[posl]==belong[posr]){
                for(int k=posl;k<=posr;k++){
                    cnt2[a[k]]++;
                    tag=max(tag,cnt2[a[k]]*T[k]);
                }
                ans[q[j].id]=tag;
                for(int k=posl;k<=posr;k++){
                    cnt2[a[k]]=0;
                }
                continue;
            }
            while(r<posr){
                r++;
                cnt1[a[r]]++;
                now=max(now,cnt1[a[r]]*T[r]);
            }
            tag=now;
            while(l>posl){
                l--;
                cnt1[a[l]]++;
                now=max(now,cnt1[a[l]]*T[l]);
            }
            ans[q[j].id]=now;
            now=tag;
            while(l<en2[i]+1){
                cnt1[a[l]]--;
                // cerr<<T[l]<<" : "<<cnt1[a[l]]<<" ";
                l++;
            }
            // cerr<<q[j].id<<" "<<posl<<" "<<posr<<"\n";
        }
    }
    for(int i=1;i<=m;i++) cout<<ans[i]<<"\n";
}

KMP

#include<iostream>
using namespace std;
const int N_KMP=1e5+10;
int fail[N_KMP],len_s_K,len_t_K;
string s_Kmp,t_Kmp;

void Fail(){
    for(int i=1;i<len_s_K;i++){//!下标从零开始
        int j=fail[i];
        while(j && (s_Kmp[i]!=s_Kmp[j])){
            j=fail[j];//?跳fail指针,因为如果失配,则一定再前一个的bored的bored
        }
        if(s_Kmp[i]==s_Kmp[j]) j++;
        fail[i+1]=j;//!如果使用0开始的下标,则集体-1,注意下标从1~len_s
    }
}

int KMP_count(){//返回个数
    int ans=0;
    for(int i=0,j=0;i<len_t_K;i++){
        while(j && (s_Kmp[j]!=t_Kmp[i])){
            j=fail[j];//?跳fail指针
        }
        if(s_Kmp[j]==t_Kmp[i]) j++;
        if(j==len_s_K){
            ans++;
            j=fail[j];
        }
    }
    return ans;
}

int main(){
    cin>>s_Kmp>>t_Kmp;
    len_s_K=s_Kmp.size();
    len_t_K=t_Kmp.size();
    Fail();
    cout<<KMP_count();
}

线段树合并

//单点修改,区间查询(线段树合并+动态开点 )
#include<iostream>
using namespace std;

#define lid d[id].ls
#define rid d[id].rs

int cnt;
struct Node{
    int sum,ls,rs;
}d[4000001];

void Update(int &id,int x,int y,int w,int pos){//修改
    if(!id) id=++cnt;
    if(x==y){
        d[id].sum+=w;
        return;
    } 
    int mid=(x+y)>>1;
    if(pos<=mid) Update(lid,x,mid,w,pos);
    else Update(rid,mid+1,y,w,pos);
    d[id].sum=d[lid].sum+d[rid].sum;
}

int Quary(int id,int x,int y,int l,int r){//查询(单点),区间使用相同的方式(pushdown时无节点就新建一个awa)
    if(!id) return 0;
    if(l<=x && y<=r) return d[id].sum;
    int mid=(x+y)>>1;
    int sum=0;
    if(l<=mid) sum=Quary(lid,x,mid,l,r);
    if(r>mid) sum+=Quary(rid,mid+1,y,l,r);
    return sum;
}

void merge(int &a,int b,int l,int r){
    if(!a){
        a=b;
        return;
    }
    if(!b) return;
    if(l==r){
        //do something...
        return;
    }
    int mid=(l+r)>>1;
    merge(d[a].ls,d[b].ls,l,mid);
    merge(d[a].rs,d[b].rs,mid+1,r);
//TODO     pushup(a); // 进行pushup
}
int main(){

}

平衡树

有旋Treap


#include<iostream>
using namespace std;
#define lid d[id].l
#define rid d[id].r
int cnt_tree,ans;

struct Treap{
    int l,r; //左孩子,右孩子
    int siz; //大小
    int cnt; //重复元素数量
    int rank; //随机出来的优先度
    int val; //值
}d[100005];

void Update_size(int id){//更新大小
    d[id].siz=d[id].cnt+d[lid].siz+d[rid].siz;
}

void lrotate(int &id){
  /* 左旋:也就是让右子节点变成根节点
   *         A                 C
   *        / \               / \
   *       B  C    ---->     A   E
   *         / \            / \
   *        D   E          B   D
   */
    int t=d[id].r; //记录右孩子
    d[id].r=d[t].l; //A的右孩子改为C的左孩子
    d[t].l=id; //C的左孩子改为A
    d[t].siz=d[id].siz;//传递size
    Update_size(id);//更新A的size
    id=t;//换根
}

void rrotate(int &id){
   /* 右旋:也就是让左子节点变成根节点
    *         A                 C
    *        / \               / \
    *       B  C    <----     A   E
    *         / \            / \
    *        D   E          B   D
    */
    int t=d[id].l;//同上
    d[id].l=d[t].r;
    d[t].r=id;
    d[t].siz=d[id].siz;
    Update_size(id);
    id=t;
}

void insert(int &id,int val){
    if(!id){ //没有点新建点
        id=++cnt_tree;
        d[id].rank=rand();
        d[id].siz=1;
        d[id].cnt=1;
        d[id].val=val;
        return;
    }
    d[id].siz++; //大小++
    if(val==d[id].val){
        d[id].cnt++; //值相同,直接扔进去
    }
    else if(val<d[id].val){
        insert(lid,val); //增加在左孩子里
        if(d[lid].rank<d[id].rank){
            rrotate(id); //为满足小根堆性质(上方优先度低于下方),需要右旋
        }
    }
    else{
        insert(rid,val); //同上
        if(d[rid].rank<d[id].rank){
            lrotate(id);
        }
    }
}
//用bool,0为未删点,1为删点
bool del(int &id,int val){
    if(!val) return false; //如果没有点,不需要修改,所以return false
    if(val==d[id].val){ //如果相等
        if(d[id].cnt>1){ //有重复元素则直接删除
            d[id].cnt--;
            d[id].siz--;
            return true;
        }
        if(lid==0 || rid==0){ //只有一个孩子,或没有孩子,不存在内讧,故直接赋值
            id=lid+rid;
            return true;
        }
        else if(d[lid].rank<d[rid].rank){ //删完还要满足小根堆,故右旋
            rrotate(id);
            return del(id,val); //删点
        }
        else{
            lrotate(id);
            return del(id,val);
        }
    }
    else if(val<d[id].val){
        bool dele=del(lid,val); //点在左孩子,记录是否成功删点
        if(dele) d[id].siz--;
        return dele;
    }
    else{
        bool dele=del(rid,val);
        if(dele) d[id].siz--;
        return dele;
    }
}

int Query_Rank(int id,int val){ //查询排名
    if(!id) return 0; //若 定义排名为比当前数小的数的个数+1 则此处应该为return 1;
    if(val==d[id].val) return d[lid].siz+1; //仅比所有左侧节点大
    else if(val<d[id].val) return Query_Rank(lid,val); //点在左孩子
    else return d[lid].siz+d[id].cnt+Query_Rank(rid,val); //1.比所有左节点大,2.比该节点的所有重复元素大,3.点在右孩子
}

int Query_Num(int id,int val){ //查询排名为val的节点值
    if(!id) return 0;
    if(val<=d[lid].siz) return Query_Num(lid,val); //节点在左孩子
    else if(val>d[lid].siz+d[id].cnt) return Query_Num(rid,val-d[lid].siz-d[id].cnt); //!节点在右孩子,但排名在右孩子里应减小
    else return d[id].val; //不在左,不在右,就只能在自己里了呗awa
}

void Query_Pre(int id,int val){ //查询前驱
    if(!id) return; //类似二分查找
    if(val>d[id].val){ //!别弄反了 
        ans=id;
        Query_Pre(rid,val);
    }
    else{
        Query_Pre(lid,val);
    }
}

void Query_Sub(int id,int val){
    if(!id) return;
    if(val<d[id].val){ //!别弄反了
        ans=id;
        Query_Sub(lid,val);
    }
    else{
        Query_Sub(rid,val);
    }
}

int main(){
    ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
    int n,root=0;
    cin>>n;
    for(int i=1;i<=n;i++){
        int op,x;
        cin>>op>>x;
        if(op==1){
            insert(root,x);
        }
        if(op==2){
            del(root,x);
        }
        if(op==3){
            cout<<Query_Rank(root,x)<<"\n";
        }
        if(op==4){
            cout<<Query_Num(root,x)<<"\n";
        }
        if(op==5){
            ans=0;
            Query_Pre(root,x);
            cout<<d[ans].val<<"\n";
        }
        if(op==6){
            ans=0;
            Query_Sub(root,x);
            cout<<d[ans].val<<"\n";
        }
    }
}

无旋Treap(FHQ)

#include<iostream>
#include<cstdlib>
using namespace std;
#define lid d[id].l
#define rid d[id].r

int cnt_tree=0,root=0,x=0,y=0,z=0;

struct Node{
    int l,r; //左右孩子
    int rank; //优先度(Treap特色)
    int val; //值
    int siz; //大小
}d[500005];

void Update(int id){ //更新大小
    d[id].siz=1+d[lid].siz+d[rid].siz;
}

int New_Node(int v){ //新建节点
    d[++cnt_tree].val=v;
    d[cnt_tree].rank=rand();
    d[cnt_tree].siz=1;
    return cnt_tree;
}

int merge(int a,int b){ //合并
    if(!a || !b){ //类似于线段树合并,有没有的直接返回另一个
        return a+b;
    }
    if(d[a].rank<d[b].rank){ //优先度上方的要小
        d[a].r=merge(d[a].r,b); //满足中序遍历顺序不变
        Update(a); //更新
        return a;
    }
    else{
        d[b].l=merge(a,d[b].l); //同上
        Update(b);
        return b;
    }
}

void split(int id,int val,int &a,int &b){ //此处为按值分裂
    if(!id) a=b=0; //如果没有节点,赋0
    else{
        if(d[id].val<=val){ //需要分裂左子树
            a=id;
            split(rid,val,rid,b);
        }
        else{ //需要分裂右子树
            b=id;
            split(lid,val,a,lid);
        }
        Update(id);
    }
}

void insert(int val){ //添加节点
    split(root,val,x,y); //分为val和val+1
    root=merge(merge(x,New_Node(val)),y); //将val加入其中
}

void del(int val){ //删除
    split(root,val,x,z); //将整棵树分为val和val+1
    split(x,val-1,x,y); //将val部分继续分为val-1与val
    y=merge(d[y].l,d[y].r); //将val节点单独剔除
    root=merge(merge(x,y),z); //还原
}

int kth(int id,int k){
    while(true){
        if(k<=d[lid].siz) id=lid; //排名小于左子树大小,说明k在左子树
        else if(k==d[lid].siz+1) return id; //太巧了,直接返回awa
        else k-=d[lid].siz+1,id=rid; //在右子树的排名需要下降
    }
}

void Query_Rank(int val){ //查询排名
    split(root,val-1,x,y); //分裂为val-1与val
    cout<<d[x].siz+1<<"\n"; //与定义相符
    root=merge(x,y); //还原
}

void Query_Num(int val){ //查询排名为val的值
    cout<<d[kth(root,val)].val<<"\n"; //直接查找即可
}

void Query_Pre(int val){ //查找前驱
    split(root,val-1,x,y); //分裂为val-1与val
    cout<<d[kth(x,d[x].siz)].val<<"\n"; //在val-1部分寻找最大的即可
    root=merge(x,y); //还原
}

void Query_Sub(int val){ //后继
    split(root,val,x,y); //分为val和val+1
    cout<<d[kth(y,1)].val<<"\n"; //在val+1部分寻找最小即可
    root=merge(x,y); //还原
}

signed main(){
    ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
    srand(123);
    int n;cin>>n;
    for(int i=1;i<=n;i++){
        int op,a;
        cin>>op>>a;
        if(op==1){
            insert(a);
        }
        if(op==2){
            del(a);
        }
        if(op==3){
            Query_Rank(a);
        }
        if(op==4){
            Query_Num(a);
        }
        if(op==5){
            Query_Pre(a);
        }
        if(op==6){
            Query_Sub(a);
        }
    }
}

Splay

#include<iostream>
using namespace std;
#define lid d[id].ch[0]
#define rid d[id].ch[1]

int root,tot;

struct Node{
    int siz,ch[2],fa,cnt,val; //不在过多介绍
}d[1000001];

void maintain(int id){ //更新大小
    d[id].siz=d[lid].siz+d[rid].siz+d[id].cnt;
}

bool get(int id){ //是否为右孩子
    return id==d[d[id].fa].ch[1];
}

void clear(int id){ //删点
    d[id].siz=lid=rid=d[id].fa=d[id].val=d[id].cnt=0;
}

void rotate(int id){ //旋转,将id转为跟,所以需要判断是否为右孩子
    //接下来以左旋为例
    int y=d[id].fa,z=d[y].fa,chk=get(id); //获取父亲和爷爷
    d[y].ch[chk]=d[id].ch[chk^1]; //将父亲的右孩子指向id的左孩子
    if(d[id].ch[chk^1]) d[d[id].ch[chk^1]].fa=y; //如果有右孩子,则设置他的父亲
    d[id].ch[chk^1]=y; //左孩子改为父亲
    d[y].fa=id; //更改父亲的父亲
    d[id].fa=z; //更改id的父亲为之前的爷爷
    if(z) d[z].ch[y==d[z].ch[1]]=id; //如果有爷爷,则通过y==d[z].ch[1]来判断应该放于左孩子还是右孩子中(直接替换)
    maintain(y); //更新
    maintain(id); //更新
    //爷爷不用更新,因为下方不会消失
}

void splay(int id){ //核心---splay
    for(int f=d[id].fa;f=d[id].fa,f;rotate(id)){ //对应6种splay的情况处理,总之,最后结果是id变为root,保持了中序遍历不变,并保持了后续log的优秀复杂度(平衡)
        if(d[f].fa) rotate(get(id)==get(f)?f:id);
    }
    root=id; //更新root
}

void insert(int val){ //插入
    if(!root){ //没有根,新建一个
        d[++tot].val=val;
        d[tot].cnt++;
        root=tot;
        maintain(root);
        return;
    }
    int id=root,f=0;
    while(1){
        if(val==d[id].val){ //如果有相同的,则cnt++即可
            d[id].cnt++;
            maintain(id);
            maintain(f);
            splay(id); //维持新进的点永远是root
            return;
        }
        f=id;
        id=d[id].ch[d[id].val<val]; //搜索树的性质
        if(!id){ //如果没有,则新建
            d[++tot].val=val;
            d[tot].cnt++;
            d[tot].fa=f;
            d[f].ch[d[f].val<val]=tot;
            maintain(tot);
            maintain(f);
            splay(tot); //维持新进的点永远是root
            return;
        }
    }
}

int Query_Rank(int val){ //查询排名
    int res=0,id=root;
    while(1){
        if(val<d[id].val){ //在左子树中
            id=lid;
        }
        else{
            res+=d[lid].siz; //先加上左子树大小
            if(!id) return res+1; //没有了,直接return
            if(val==d[id].val){ //太巧了,直接返回即可
                splay(id); //维护root,为后续del做准备
                return res+1;
            }
            res+=d[id].cnt;
            id=rid; //在右子树中
        }
    }
}

int kth(int val){ //查询排名为val的值
    int id=root;
    while(1){
        if(lid && val<=d[lid].siz){ //在左子树
            id=lid;
        }
        else{ //在右子树
            val-=d[id].cnt+d[lid].siz;
            if(val<=0){ //如果减为非正数,证明就是id了
                splay(id); //维护splay性质
                return d[id].val; //返回值
            }
            id=rid; //否则继续在右子树中寻找
        }
    }
}

int Query_Pre(){ //因为insert了,所以root已经是val了
    int id=d[root].ch[0]; //正常的搜索树的查找方式
    if(!id) return id;
    while(rid) id=rid;
    splay(id);
    return id;
}

int Query_Sub(){ //同上
    int id=d[root].ch[1];
    if(!id) return id;
    while(lid) id=lid;
    splay(id);
    return id;
}

void del(int val){ //删除
    Query_Rank(val); //先查询,使得val为root
    if(d[root].cnt>1){ //太巧了,直接--;
        d[root].cnt--;
        maintain(root);
        return;
    }
    if(!d[root].ch[0] && !d[root].ch[1]){ //孤立无援,真是令人惋惜
        clear(root);
        root=0;
        return;
    }
    if(!d[root].ch[0]){ //直接使右孩子代替root
        int id=root;
        root=d[root].ch[1];
        d[root].fa=0;
        clear(id);
        return;
    }
    if(!d[root].ch[1]){ //直接使左孩子代替root
        int id=root;
        root=d[root].ch[0];
        d[root].fa=0;
        clear(id);
        return;
    }
    int id=root,x=Query_Pre(); //找到比他小的最大数
    d[rid].fa=x; //将跟的右孩子直接接在前驱上
    d[x].ch[1]=rid;
    clear(id);
    maintain(root);
}

int main(){
    ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
    int n;
    cin>>n;
    for(int i=1;i<=n;i++){
        int op,x;
        cin>>op>>x;
        if(op==1){
            insert(x);
        }
        if(op==2){
            del(x);
        }
        if(op==3){
            cout<<Query_Rank(x)<<"\n";
        }
        if(op==4){
            cout<<kth(x)<<"\n";
        }
        if(op==5){
            insert(x);
            cout<<d[Query_Pre()].val<<"\n";
            del(x);
        }
        if(op==6){
            insert(x);
            cout<<d[Query_Sub()].val<<"\n";
            del(x);
        }
    }
}

杂项(不知道算什么的东西)

矩阵快速幂

#include<iostream>
#include<cstring>
using namespace std;
long long mod=1;

struct Mat{
    long long m,n;
    long long a[11][11];
    void resize(long long x,long long y){
        n=x;
        m=y;
    }
    Mat operator * (const Mat & A) const{
        Mat res;
        res.resize(n,A.m);
        memset(res.a,0,sizeof(res.a));
        
        for(int i=1;i<=n;i++){
            for(int j=1;j<=A.m;j++){
                for(int k=1;k<=m;k++){
                    res.a[i][j]=(a[i][k]*A.a[k][j]+res.a[i][j])%mod;
                }
            }
        } 
        return res;
    }
    
    
};

Mat qpow(Mat A,long long b){
    Mat res;
    res.resize(2,2);
    res.a[1][1]=res.a[1][2]=res.a[2][1] =res.a[2][2]=1;
    while(b){
        if(b&1) res=res*A;
        
        A=A*A;
        
        b>>=1;
    }
    return res;
}
    
int main(){
    long long n;
    cin>>n>>mod;
    Mat b;
    b.resize(2,2);
    b.a[1][1]=b.a[1][2]=b.a[2][1]=1;
    b.a[2][2]=0;
    Mat re=qpow(b,n-3);
    printf("%lld",(re.a[1][1]+re.a[1][2])%mod);
}

动态规划DP

背包DP

01背包

#include<iostream>
#include<cmath>
using namespace std;
int n[1001],v[1001],f[1001];//使用j空间能出现的最大价值 
int main(){
     int N,V;
     cin>>N>>V;
     for(int i=1;i<=N;i++){
         cin>>v[i]>>n[i];
     }
     for(int i=1;i<=N;i++){
         for(int j=V;j>=v[i];j--){
             f[j]=max(f[j],f[j-v[i]]+n[i]);
        }
     }
     int l=0;
     for(int i=1;i<=V;i++){
         l=max(l,f[i]);
     }
     cout<<l;
}

多重背包

#include<iostream>
#include<cmath>
using namespace std;
int n[1001],v[1001],f[1001],c[1001];//使用j空间能出现的最大价值 
int main(){
     int N,V;
     cin>>N>>V;
     for(int i=1;i<=N;i++){
         cin>>v[i]>>n[i]>>c[i];
     }
     for(int i=1;i<=N;i++){
         for(int k=1;k<=min(V/v[i],c[i]);k++)
             for(int j=V;j>=v[i]*k;j--){
                 f[j]=max(f[j],f[j-k*v[i]]+k*n[i]);
            }
     }
     int l=0;
     for(int i=1;i<=V;i++){
         l=max(l,f[i]);
     }
     cout<<l;
}

完全背包

#include<iostream>
#include<cmath>
using namespace std;
int n[1001],v[1001],f[1001];
int main(){
     int N,V;
     cin>>V>>N;
     for(int i=1;i<=N;i++){
         cin>>v[i]>>n[i];
     }
     for(int i=1;i<=N;i++){
         for(int k=1;k<=V/v[i];k++)
             for(int j=V;j>=v[i]*k;j--){
                 f[j]=max(f[j],f[j-k*v[i]]+k*n[i]);
            }
     }
     int l=0;
     for(int i=1;i<=V;i++){
         l=max(l,f[i]);
     }
     cout<<"max="<<l;
}

二进制分组背包(放到混合背包里了)

#include<iostream>
#include<cmath>
using namespace std;
int n[1001],v[1001],f[1001];
int main(){
     int N,V;
     cin>>V>>N;
     for(int i=1;i<=N;i++){
         cin>>v[i]>>n[i];
     }
     for(int i=1;i<=N;i++){
         for(int k=1;k<=V/v[i];k++)
             for(int j=V;j>=v[i]*k;j--){
                 f[j]=max(f[j],f[j-k*v[i]]+k*n[i]);
            }
     }
     int l=0;
     for(int i=1;i<=V;i++){
         l=max(l,f[i]);
     }
     cout<<"max="<<l;
}

线性DP

LIS

#include<iostream>
#include<algorithm>
using namespace std;

int n,t[1000001],c[1000001];

inline int lowbit(int x){
    return x&(-x);
}

void Update(int x,int w){
    while(x<=n){c[x]=max(c[x],w),x+=lowbit(x);}
}

int Sum(int x){
    int ans=0;
    while(x){
        ans=max(ans,c[x]);
        x-=lowbit(x);
    }
    return ans;
}

struct Node{
    int id,val;
}a[1000001];

bool cmp(Node a,Node b){
    return a.val<b.val;
}

int main(){
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>a[i].val;
        a[i].id=i;
    }
    sort(a+1,a+1+n,cmp);
    int ans=0;
    for(int i=1;i<=n;i++){
        t[i]=Sum(a[i].id)+1;
        Update(a[i].id,t[i]);
        ans=max(ans,t[i]);
    }
    cout<<ans;
}

最长公共子序列

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
int dp[1001][1001];
char a[1001],b[1001];
int main(){
    scanf("%s%s",a+1,b+1);
    int maxn=0;
    for(int i=1;b[i];i++){
        for(int j=1;a[j];j++){
            if(b[i]==a[j]) dp[i][j]=dp[i-1][j-1]+1;
            if(maxn<dp[i][j]) maxn=dp[i][j];
        }
    }
    cout<<maxn;
}
posted @ 2024-09-29 09:15  QEDQEDQED  阅读(15)  评论(0编辑  收藏  举报