OI 模板合集

update on 2023.10:
这篇博客的原本意义是 方便直接复制 / 快速复习,但部分原有代码存在本质错误,完全没有起到这个作用,故重构。
由于折叠代码块在某些 markdown 编辑器中不支持,现已全文取消折叠,请善用页面右侧标题 / Ctrl+F 快速跳转。

以下是本人平时的缺省源,所以下文的代码里可能存在部分 inline 缩写为 il

#include<bits/stdc++.h>
#define il inline
using namespace std;
il long long read()
{
    long long xr=0,F=1; char cr;
    while(cr=getchar(),cr<'0'||cr>'9') if(cr=='-') F=-1;
    while(cr>='0'&&cr<='9')
        xr=(xr<<3)+(xr<<1)+(cr^48),cr=getchar();
    return xr*F;
}

输入输出优化

int 快读

il int read()
{
    int xr=0,F=1; char cr;
    while(cr=getchar(),cr<'0'||cr>'9') if(cr=='-') F=-1;
    while(cr>='0'&&cr<='9')
        xr=(xr<<3)+(xr<<1)+(cr^48),cr=getchar();
    return xr*F;
}

double 快读

il double dbread()
{
    double X=0,Y=1.0; int F=1; char cr=0;
    while(!isdigit(cr)) {if(cr=='-') F=-1;cr=getchar();}
    while(isdigit(cr)) X=X*10+(cr^48),cr=getchar();
    cr=getchar();
    while(isdigit(cr)) X+=(Y/=10)*(cr^48),cr=getchar();
    return X*F;
}

int 快写

void write(int x)
{
    if(x<0) putchar('-'),x=-x;
    if(x>9) write(x/10); putchar(x%10+'0');
}

动态规划

DP 还存在什么板子吗(?

01 背包

for(int i=1;i<=m;i++)
    for(int j=t;j;j--)
        if(j-w[i]>=0) f[j]=max(f[j],f[j-w[i]]+c[i]);

树形背包

void dfs(int u,int fa)
{
    siz[u]=1,f[u][1]=w[u];
    for(auto v:e[u]) if(v^fa)
    {
        dfs(v,u);
        for(int j=siz[u];j;j--)
            for(int k=0;k<=siz[v];k++)
                f[u][j+k]=max(f[u][j+k],f[u][j]+f[v][k]);
        siz[u]+=siz[v];
    }
}

多重背包(二进制优化)

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+5;
int n,t,c[N],w[N];
int f[N],cnt;
int main()
{
    scanf("%d%d",&n,&t);
    for(int i=1,W,C,m;i<=n;i++)
    {
        scanf("%d%d%d",&C,&W,&m);
        int j;
        for(j=0;(1<<(j+1))-1<=m;j++) w[++cnt]=(1<<j)*W,c[cnt]=(1<<j)*C;
        w[++cnt]=W*(m-((1<<j)-1)),c[cnt]=C*(m-((1<<j)-1));
    }
    for(int i=1;i<=cnt;i++)
        for(int j=t;j;j--)
            if(j-w[i]>=0) f[j]=max(f[j],f[j-w[i]]+c[i]); 
    cout<<f[t]<<endl;
    return 0;
}

图论

平时的习惯是图用链前树用 vector

最短路

Floyd

循环顺序不能颠倒。

for(int k=1;k<=n;k++) for(int i=1;i<=n;i++)
    for(int j=1;j<=n;j++) f[i][j]=min(f[i][j],f[i][k]+f[k][j]);

SPFA

queue<int> q;
int in[N],dis[N];
il void spfa(int s)
{
    for(int i=1;i<=n;i++) dis[i]=inf;
    dis[s]=0,in[s]=1; q.push(s);
    while(!q.empty())
    {
        int u=q.front(); in[u]=0,q.pop();
        for(int i=head[u];i;i=e[i].nxt)
        {
            int v=e[i].to;
            if(dis[v]>dis[u]+e[i].w) 
            {
                dis[v]=dis[u]+e[i].w;
                if(!in[v]) in[v]=1,q.push(v);
            }
        }
    }
}

SPFA 判负环

这里用的是最短路长度判负环,而非入队次数。注意多测清空。

int dis[N],in[N],len[N];
il bool spfa(int s)
{
    queue<int> q;
    for(int i=1;i<=n;i++) dis[i]=inf,in[i]=0;
    dis[s]=0,in[s]=1,len[s]=0; q.push(s);
    while(!q.empty())
    {
        int u=q.front(); in[u]=0,q.pop();
        for(int i=head[u];i;i=e[i].nxt)
        {
            int v=e[i].to; 
            if(dis[v]>dis[u]+e[i].w)
            {
                len[v]=len[u]+1,dis[v]=dis[u]+e[i].w;
                if(len[v]>=n) return 0;
                if(!in[v]) in[v]=1,q.push(v);
            }
        }
    }
    return 1;
}

Dijkstra

priority_queue<pii,vector<pii>,greater<pii> >q;
void dij(int s)
{
    dis[s]=0;
    q.push(pii(0,s));
    while(!q.empty())
    {
        int u=q.top().se,f=q.top().fi; q.pop();
        if(f!=dis[u])continue;
        for(int i=head[u];i;i=e[i].nxt)
        {
            int v=e[i].to,w=e[i].w;
            if(dis[v]>dis[u]+w)
            {
                dis[v]=dis[u]+w;
                q.push(pii(dis[v],v));
            }
        }
    }
}

连通性相关(tarjan 系列)

强连通分量

stack<int> q;
void tarjan(int u)
{
    dfn[u]=++tot;low[u]=dfn[u];q.push(u);in[u]=1;
    for(int i=head[u];i;i=e[i].nxt)
    {
        int v=e[i].to;
        if(!dfn[v]) {tarjan(v);low[u]=min(low[u],low[v]);}
        else if(in[v]) low[u]=min(low[u],dfn[v]);
    }
    if(low[u]==dfn[u])
    {
        num++;
        while(!q.empty())
        {
            if(q.top()==u) {in[u]=0,bel[u]=num,q.pop();break;}
            in[q.top()]=0,bel[q.top()]=num,q.pop();
        }
    }
}

割点

注意根的特判。

int dfn[N],low[N],tot;
bool flag[N];
void tarjan(int u,int rt)
{
    dfn[u]=low[u]=++tot;int qwq=0;
    for(int i=head[u];i;i=e[i].nxt)
    {
        int v=e[i].to;
        if(!dfn[v]) 
        {
            tarjan(v,rt);
            low[u]=min(low[u],low[v]);
            if(low[v]>=dfn[u]&&rt!=u) flag[u]=1;
            qwq++;
        }
        else low[u]=min(low[u],dfn[v]);
    }
    if(qwq>1&&u==rt) flag[u]=1;
}

点双连通分量

特判孤立点。

int dfn[N],low[N],tot,num;
stack<int> q;
vector<int> ans[N];
void tarjan(int u,int fa)
{
    dfn[u]=low[u]=++tot; q.push(u);
    int son=0;
    for(int i=head[u];i;i=e[i].nxt)
    {
        int v=e[i].to; if(v==fa) continue;
        if(!dfn[v]) 
        {
            son=1;
            tarjan(v,u),low[u]=min(low[u],low[v]);
            if(low[v]>=dfn[u])
            {
                num++;
                while(q.top()!=u)
                {
                    int x=q.top();
                    ans[num].push_back(q.top()),q.pop();
                    if(x==v) break;
                }
                ans[num].push_back(u);
            }
        }
        else low[u]=min(low[u],dfn[v]);
    }
    if(!fa&&!son) ans[++num].push_back(u);
}

割边(桥)

upd: 这个要注意是否有重边,有的话应该记录经过的上一条边而非上一个点。

void tarjan(int u,int fa)
{
    low[u]=dfn[u]=++tot;
    for(int i=head[u];i;i=e[i].nxt)
    {
        int v=e[i].to;if(v==fa) continue;
        if(!dfn[v])
        {
            tarjan(v,u);
            low[u]=min(low[u],low[v]);
            if(low[v]>dfn[u]) flag[(i+1)/2]=1;
        }
        else low[u]=min(low[u],dfn[v]);
    }
}

边双连通分量

int dfn[N],low[N],tot,num;
stack<int> q;
vector<int> ans[N];
void tarjan(int u,int lst)
{
    dfn[u]=low[u]=++tot; q.push(u);
    for(int i=head[u];i;i=e[i].nxt)
    {
        int v=e[i].to; if(i==(lst^1)) continue;
        if(!dfn[v]) tarjan(v,i),low[u]=min(low[u],low[v]);
        else low[u]=min(low[u],dfn[v]);
    }
    if(dfn[u]==low[u])
    {
        num++;
        while("qwq")
        {
            int x=q.top(); q.pop(),ans[num].push_back(x);
            if(x==u) break;
        }
    }
}

图的匹配 & 网络流

匈牙利

int f[N][N],vis[N],mat[N];
bool dfs(int u)
{
    for(int i=1;i<=m;i++) if(!vis[i]&&f[u][i])
    {
        vis[i]=1;
        if(!mat[i]||dfs(mat[i])) {mat[i]=u;return 1;}
    }
    return 0;
}

for(int i=1;i<=n;i++) dfs(i),memset(vis,0,sizeof(vis));

EK 最大流

int vis[N],pre[N],dis[N];
bool bfs(int s,int t)
{
    for(int i=1;i<=n;i++) vis[i]=0,pre[i]=-1,dis[i]=inf;
    queue<int> q;q.push(s);
    vis[s]=1;
    while(!q.empty())
    {
        int u=q.front();q.pop();
        if(u==t) return 1;
        for(int i=head[u];i;i=e[i].nxt)
        {
            int v=e[i].to,w=e[i].w;
            if(vis[v]||!w) continue;
            vis[v]=1,pre[v]=i;
            dis[v]=min(dis[u],w);
            q.push(v);
        }
    }
    return 0;
}
void upd(int s,int t)
{
    int now=t;
    while(now!=s)
    {
        int i=pre[now];
        e[i].w-=dis[t];
        e[i^1].w+=dis[t];
        now=e[i^1].to;
    }
    ans+=dis[t];
}

Dinic 最大流

il void add(int u,int v,int w)
{
    e[++cnt]={head[u],v,w};head[u]=cnt;
    e[++cnt]={head[v],u,0};head[v]=cnt;
}
int dis[N],now[N];
queue<int> q;
il bool bfs()
{
    for(int i=1;i<=n;i++) dis[i]=inf,now[i]=head[i];
    dis[s]=0;q.push(s);
    while(!q.empty())
    {
        int u=q.front(); q.pop();
        for(int i=head[u];i;i=e[i].nxt)
        {
            int v=e[i].to;
            if(e[i].w&&dis[v]==inf) dis[v]=dis[u]+1,q.push(v);
        }
    }
    return dis[t]!=inf;
}
int dfs(int u,int sum)
{
    int res=0;
    if(u==t) return sum;
    for(int i=now[u];i&&sum;i=e[i].nxt)
    {
        now[u]=i; int v=e[i].to;
        if(!e[i].w||dis[v]!=dis[u]+1) continue;
        int k=dfs(v,min(sum,e[i].w));
        e[i].w-=k,e[i^1].w+=k,sum-=k,res+=k;
    }
    return res;
}

EK 费用流

bool spfa()
{
    queue<int> q;
    for(int i=1;i<=n;i++) dis[i]=mn[i]=inf,pre[i]=-1,in[i]=0;
    dis[s]=0,in[s]=1;q.push(s);
    while(!q.empty())
    {
        int u=q.front();q.pop();in[u]=0;
        for(int i=head[u];i;i=e[i].nxt)
        {
            int v=e[i].to,w=e[i].w;
            if(!w) continue;
            if(dis[v]>dis[u]+e[i].c)
            {
                dis[v]=dis[u]+e[i].c;
                mn[v]=min(mn[u],e[i].w);
                pre[v]=i;
                if(!in[v]) in[v]=1,q.push(v);
            }
        }
    }
    if(dis[t]==inf) return 0;
    else return 1;
}
int ans1,ans2;
void upd()
{
    int now=t;
    while(now!=s)
    {
        int i=pre[now];
        e[i].w-=mn[t],e[i^1].w+=mn[t];
        now=e[i^1].to;
    }
    ans1+=mn[t];ans2+=dis[t]*mn[t];
}

Dinic 费用流(zkw 费用流)

int dis[N],in[N],now[N];
queue<int> q;
bool spfa()
{
    for(int i=1;i<=n;i++) dis[i]=inf,now[i]=head[i];
    dis[s]=0,in[s]=1; q.push(s);
    while(!q.empty())
    {
        int u=q.front(); in[u]=0;q.pop();
        for(int i=head[u];i;i=e[i].nxt)
        {
            int v=e[i].to; 
            if(e[i].w&&dis[v]>dis[u]+e[i].c)
            {
                dis[v]=dis[u]+e[i].c;
                if(!in[v]) in[v]=1,q.push(v);
            }
        }
    }
    return dis[t]!=inf;
}
int dfs(int u,int sum)
{
    if(u==t) return sum;
    in[u]=1; int res=0;
    for(int i=now[u];i&&sum;i=e[i].nxt)
    {
        now[u]=i; int v=e[i].to;
        if(e[i].w&&dis[v]==dis[u]+e[i].c&&!in[v])
        {
            int k=dfs(v,min(e[i].w,sum));
            e[i].w-=k,e[i^1].w+=k,sum-=k,res+=k;
        }
    }
    in[u]=0;return res;
}

上下界最大流

const int N=1e5+5,inf=1e9;
struct edge{
    int nxt,to,w;
}e[N<<1];
int head[N],cnt=1;
void add(int u,int v,int w)
{
    e[++cnt]={head[u],v,w};head[u]=cnt;
    e[++cnt]={head[v],u,0};head[v]=cnt;
}
int n,m,s,t;
int dis[N],now[N];
struct qaq{
    int u,v,l,r;
}E[N]; 
bool bfs(int s,int t) 
{
    queue<int> q;
    for(int i=s;i<=t;i++) dis[i]=inf,now[i]=head[i];
    dis[s]=0,q.push(s);
    while(!q.empty())
    {
        int u=q.front(); q.pop();
        for(int i=head[u];i;i=e[i].nxt)
        {
            int v=e[i].to;
            if(dis[v]!=inf||!e[i].w) continue;
            dis[v]=dis[u]+1,q.push(v);
        }
    }
    return dis[t]!=inf;
}
int dfs(int u,int t,int sum)
{
    if(u==t) return sum;
    int res=0;
    for(int i=now[u];i&&sum;i=e[i].nxt)
    {
        int v=e[i].to; now[u]=i;
        if(dis[v]!=dis[u]+1||!e[i].w) continue;
        int k=dfs(v,t,min(e[i].w,sum));
        e[i].w-=k,e[i^1].w+=k;
        sum-=k,res+=k;
    }
    return res;
}
int W[N];
int calc(int n,int m,int s,int t)
{
    memset(head,0,sizeof(head)),cnt=1;
    memset(W,0,sizeof(W));
    for(int i=1;i<=m;i++)
    {
        int u=E[i].u,v=E[i].v,l=E[i].l,r=E[i].r;
        add(u,v,r-l),W[u]-=l,W[v]+=l;
    }
    int S=0,T=n+1;int sum=0;
    add(t,s,inf);
    for(int i=1;i<=n;i++)
    {
        if(W[i]>0) add(S,i,W[i]),sum+=W[i];
        else add(i,T,-W[i]);
    }
    int res=0,ans=0;
    while(bfs(S,T)) res+=dfs(S,T,inf);
    if(res!=sum) return -1;
    while(bfs(s,t)) ans+=dfs(s,t,inf);
    return ans;
}

树上问题

Kruskal

bool cmp(node a,node b) {return a.w<b.w;}
int find(int x)
{
    if(fa[x]==x) return x;
    return fa[x]=find(fa[x]);
}
int main()
{
    scanf("%d%d",&n,&m); 
    for(int i=1;i<=n;i++) fa[i]=i;
    for(int i=1;i<=m;i++) scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);
    sort(e+1,e+m+1,cmp);
    for(int i=1;i<=m;i++)
    {
        if(find(e[i].u)==find(e[i].v)) continue;
        ans+=e[i].w;
        fa[find(e[i].v)]=find(e[i].u);
        if(cnt==n-2) {cnt++;break;}
    }
    printf("%d",ans);
    return 0;
}

堆优化 Prim

int vis[N];
priority_queue<pii,vector<pii>,greater<pii> >q;
int Prim(int s)
{
    int ans=0;
    q.push(pii(0,s));
    while(!q.empty())
    {
        int w=q.top().fi,u=q.top().se;q.pop();
        if(vis[u]) continue;
        ans=max(ans,w);vis[u]=1;
        for(int i=head[u];i;i=e[i].nxt)
        {
            int v=e[i].to;
            if(vis[v]) continue;
            q.push(pii(e[i].w,v));
        }
    }
    return ans;
}

倍增 LCA

循环边界不要写 __lg(n),这样会把 \(\log\) 跑满,常数真的很大。

int f[21][N],dep[N];
void init(int u,int fa)
{
    f[0][u]=fa,dep[u]=dep[fa]+1;
    for(int i=1;i<=__lg(dep[u]);i++) f[i][u]=f[i-1][f[i-1][u]];
    for(auto v:e[u]) if(v^fa) init(v,u);
}
int lca(int x,int y)
{
    if(dep[x]<dep[y]) swap(x,y);
    for(int i=__lg(dep[x]);i>=0;i--) if(dep[f[i][x]]>=dep[y]) x=f[i][x];
    for(int i=__lg(dep[x]);i>=0;i--) if(f[i][x]!=f[i][y]) x=f[i][x],y=f[i][y];
    return x==y?x:f[0][x];
}

树剖 LCA & k 级祖先

int dfn[N],tot,y[N],dep[N],siz[N],son[N],top[N],fa[N];
void dfs1(int u,int ff)
{
    dep[u]=dep[ff]+1,siz[u]=1,fa[u]=ff;
    for(auto v:e[u]) if(v^ff)
    {
        dfs1(v,u),siz[u]+=siz[v];
        if(siz[v]>siz[son[u]]) son[u]=v;
    }
}
void dfs2(int u,int tp)
{
    dfn[u]=++tot,y[tot]=u,top[u]=tp;
    if(son[u]) dfs2(son[u],tp);
    for(auto v:e[u]) if(v!=fa[u]&&v!=son[u]) dfs2(v,v);
}
il int lca(int x,int y)
{
    while(top[x]!=top[y])
    {
        if(dep[top[x]]<dep[top[y]]) swap(x,y);
        x=fa[top[x]];
    }
    return dep[x]<dep[y]?x:y;
}
il int kfa(int x,int k)
{
    int dp=dep[x]-k;
    while(dep[top[x]]>dp) x=fa[top[x]];
    return y[dfn[x]-(dep[x]-dp)];
}

dfs 序 LCA

int dfn[N],tot,st[20][N],dep[N];
il int get(int x,int y) {return dep[x]<dep[y]?x:y;}
void dfs(int u,int fa)
{
    dfn[u]=++tot,st[0][tot]=fa,dep[u]=dep[fa]+1;
    for(auto v:e[u]) if(v^fa) dfs(v,u);
}
void init()
{
    dfs(rt,0);
    for(int i=1;i<=__lg(n);i++) for(int j=1;j<=n-(1<<i)+1;j++) 
        st[i][j]=get(st[i-1][j],st[i-1][j+(1<<i-1)]);
}
int lca(int x,int y)
{
    if(x==y) return x;
    if((x=dfn[x])>(y=dfn[y])) swap(x,y);
    int len=__lg(y-x);
    return get(st[len][x+1],st[len][y-(1<<len)+1]);
}

树上 k 级祖先

vector<int> U[N],D[N],e[N];
int dep[N],mxdep[N],son[N],fa[N],top[N];
int f[21][N],highbit[N];
void dfs1(int u,int ff)
{
    mxdep[u]=dep[u]=dep[ff]+1,fa[u]=ff,f[0][u]=ff;
    for(int i=1;i<=__lg(dep[u]);i++) f[i][u]=f[i-1][f[i-1][u]];
    for(auto v:e[u]) if(v^ff)
    {
        dfs1(v,u);
        if(mxdep[v]>mxdep[u]) son[u]=v,mxdep[u]=mxdep[v];
    }
}
void dfs2(int u,int tp)
{
    top[u]=tp;
    if(u==tp)
    {
        for(int i=0,f=u;i<=mxdep[u]-dep[u];i++) U[u].push_back(f),f=fa[f];
        for(int i=0,f=u;i<=mxdep[u]-dep[u];i++) D[u].push_back(f),f=son[f];
    }
    if(son[u]) dfs2(son[u],tp);
    for(auto v:e[u]) if(v!=son[u]) dfs2(v,v);
}
il int kfa(int x,int k)
{
    if(!k) return x;
    x=f[highbit[k]][x],k^=(1<<highbit[k]),k-=dep[x]-dep[top[x]],x=top[x];
    assert(abs(k)<=mxdep[x]-dep[x]);
    return k>=0?U[x][k]:D[x][-k];
}

树剖维护树链 & 子树权值和

#define int long long
const int N=1e5+5;
int rt,mod;
int n,m,a[N],y[N];
il void add(int &x,int y) {x+=y;if(x>=mod) x-=mod;}
struct segtree
{
    #define ls (now<<1)
    #define rs (now<<1|1)
    #define mid (l+r>>1)
    int tr[N<<2],lz[N<<2];
    void build(int now,int l,int r)
    {
        if(l==r) {tr[now]=a[y[l]]%mod;return;}
        build(ls,l,mid),build(rs,mid+1,r);
        tr[now]=(tr[ls]+tr[rs])%mod;
    }
    void modify(int now,int l,int r,int ml,int mr,int k)
    {
        tr[now]+=(mr-ml+1)*k;
        if(l==ml&&r==mr) {add(lz[now],k);return;}
        if(mr<=mid) modify(ls,l,mid,ml,mr,k);
        else if(ml>mid) modify(rs,mid+1,r,ml,mr,k);
        else modify(ls,l,mid,ml,mid,k),modify(rs,mid+1,r,mid+1,mr,k);
    }
    int query(int now,int l,int r,int ml,int mr)
    {
        if(l==ml&&r==mr) return tr[now];
        int res=lz[now]*(mr-ml+1)%mod;
        if(mr<=mid) return (res+query(ls,l,mid,ml,mr))%mod;
        else if(ml>mid) return (res+query(rs,mid+1,r,ml,mr))%mod;
        else return (res+query(ls,l,mid,ml,mid)+query(rs,mid+1,r,mid+1,mr))%mod;
    }
}seg;
vector<int> e[N];
int fa[N],dfn[N],tot,siz[N],son[N],top[N],dep[N];
void dfs1(int u,int ff)
{
    fa[u]=ff,siz[u]=1,dep[u]=dep[ff]+1;
    for(auto v:e[u]) if(v^ff) 
    {
        dfs1(v,u),siz[u]+=siz[v];
        if(siz[v]>siz[son[u]]) son[u]=v;
    }
}
void dfs2(int u,int tp)
{
    dfn[u]=++tot,y[tot]=u,top[u]=tp;
    if(son[u]) dfs2(son[u],tp);
    for(auto v:e[u]) if(v!=fa[u]&&v!=son[u]) dfs2(v,v);
}
il void addline(int x,int y,int k)
{
    while(top[x]!=top[y])
    {
        if(dep[top[x]]<dep[top[y]]) swap(x,y);
        seg.modify(1,1,n,dfn[top[x]],dfn[x],k);
        x=fa[top[x]];
    }
    if(dep[x]>dep[y]) swap(x,y);
    seg.modify(1,1,n,dfn[x],dfn[y],k);
}
il int queryline(int x,int y)
{
    int res=0;
    while(top[x]!=top[y])
    {
        if(dep[top[x]]<dep[top[y]]) swap(x,y);
        add(res,seg.query(1,1,n,dfn[top[x]],dfn[x]));
        x=fa[top[x]];
    }
    if(dep[x]>dep[y]) swap(x,y);
    add(res,seg.query(1,1,n,dfn[x],dfn[y]));
    return res;
}
il void addsub(int x,int k) {seg.modify(1,1,n,dfn[x],dfn[x]+siz[x]-1,k);}
il int querysub(int x) {return seg.query(1,1,n,dfn[x],dfn[x]+siz[x]-1);}

prufer 序列

namespace sub1
{
    int fa[N],a[N],son[N];
    void solve()
    {
        for(int i=1;i<n;i++) fa[i]=read(),son[fa[i]]++;
        for(int i=1,j=1;i<=n-2;i++,j++)
        {
            while(son[j]) j++;
            a[i]=fa[j];
            while(i<=n-2&&!(--son[a[i]])&&a[i]<j) a[i+1]=fa[a[i]],i++;
        }
        int ans=0;
        for(int i=1;i<=n-2;i++) ans^=i*a[i];
        printf("%lld\n",ans);
    }
}
namespace sub2
{
    int fa[N],a[N],son[N];
    void solve()
    {
        for(int i=1;i<=n-2;i++) a[i]=read(),son[a[i]]++;
        a[n-1]=n;
        for(int i=1,j=1;i<n;i++,j++)
        {
            while(son[j]) j++;
            fa[j]=a[i];
            while(i<n&&!(--son[a[i]])&&a[i]<j) fa[a[i]]=a[i+1],i++;
        }
        int ans=0;
        for(int i=1;i<n;i++) ans^=i*fa[i];
        printf("%lld\n",ans);
    }
}

其他

欧拉回路

stack<int> q;
void dfs(int u)
{
    for(int i=head[u];i;i=head[u])
    {
        head[u]=e[i].nxt; 
        int v=e[i].to; dfs(v);
    }
    q.push(u);
}

数学

线性代数

快速幂

int qpow(int n,int k)
{
    int res=1;
    for(;k;n=n*n%mod,k>>=1) if(k&1) res=res*n%mod;
    return res;
}

矩阵快速幂

il void add(int &x,int y) {x+=y;if(x>=mod) x-=mod;}
struct matrix
{
    int f[2][2];
    matrix() {memset(f,0,sizeof(f));}
    void init() {f[0][0]=f[1][1]=1;}
    friend matrix operator *(const matrix &a,const matrix &b) 
    {
        matrix res;
        for(int i=0;i<2;i++) for(int k=0;k<2;k++)
            for(int j=0;j<2;j++) add(res.f[i][j],a.f[i][k]*b.f[k][j]%mod);
        return res;
    }
};
matrix qpow(matrix n,int k)
{
    matrix res; res.init();
    for(;k;n=n*n,k>>=1) if(k&1) res=res*n;
    return res;
}

高斯消元

void gauss()
{
    for(int j=1;j<=n;j++)
    {
        for(int i=j;i<=n;i++) if(f[i][j]) {swap(f[i],f[j]);break;}
        if(fabs(f[j][j])<eps) {printf("No Solution\n");exit(0);}
        for(int i=1;i<=n;i++)
        {
            if(i==j) continue;
            double K=f[i][j]/f[j][j];
            for(int k=1;k<=n+1;k++) f[i][k]-=K*f[j][k];
        }
    }
    for(int i=1;i<=n;i++) f[i][n+1]/=f[i][i];
}

行列式

struct matrix
{
    int n,m,f[N][N];
    matrix() {n=m=0;memset(f,0,sizeof(f));}
    int * operator [](const int &x) {return f[x];}
};
int det(matrix f)
{
    int res=1;
    for(int i=1;i<=n;i++)
        for(int j=i+1;j<=n;j++)
        {
            while(f[i][i])
            {
                int div=f[j][i]/f[i][i];
                for(int k=i;k<=n;k++) f[j][k]=(f[j][k]-1ll*f[i][k]*div%mod+mod)%mod;
                swap(f.f[i],f.f[j]),res*=-1;
            }
            swap(f.f[i],f.f[j]),res*=-1;
        }
    for(int i=1;i<=n;i++) res=1ll*res*f[i][i]%mod;
    return (res+mod)%mod;
}  

线性基

贪心法

int n,p[N];
il void ins(int x)
{
    for(int i=49;i>=0;i--) if(x>>i&1)
    {
        if(!p[i]) {p[i]=x;return;}
        x^=p[i];
    }
}

如果不想写高斯消元,可以在贪心后调整,变成与高斯消元法相同的形式:

for(int i=63;i>=0;i--)
{
    if(!p[i]) continue;
    for(int j=63;j>i;j--) if((p[j]>>i)&1) p[j]^=p[i];
}

数论

欧拉函数

要复习

int now=m;
for(int i=2;i*i<=m;i++)
{
    if(now%i==0)
    {
        phi=phi*(i-1)/i;
        while(now%i==0) now/=i;
    }
}
if(now>1) phi=phi*(now-1)/now;

exgcd

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

Lucas 定理

int c(int n,int m){
    if(m>n) return 0;
    return jc[n]*qpow(jc[m],mod-2)%mod*qpow(jc[n-m],mod-2)%mod;
}
int lucas(int n,int m){
    if(!m) return 1;
    return lucas(n/mod,m/mod)*c(n%mod,m%mod)%mod;
}

原根

inline bool check1(int x)//check原根存在性 
{
    if(x==2||x==4) return 1;
    if(x%2==0) x/=2;
    if(x%2==0) return 0;
    //bool flag=0;
    for(int i=2;i*i<=x;i++)
    {
        if(x%i==0)
        {
            while(x%i==0) x/=i;
            return (x==1);
        }
    }
    return 1;
}
inline bool check2(int x,int n)//判定合法性
{
    if(__gcd(x,n)>1) return 0;
    int m=phi[n];tot=0;
    for(int i=2;i*i<=m;i++) 
    {
        if(m%i==0)
        {
            fac[++tot]=i;
            while(m%i==0) m/=i;
        }
    }
    if(m>1) fac[++tot]=m;
    for(int i=1;i<=tot;i++)
        if(qpow(x,phi[n]/fac[i],n)==1) return 0;
    return 1;
}

BSGS

#define int long long
int p,b,n;
unordered_map<int,int> mp;
int qpow(int n,int k)
{
    int res=1;
    for(;k;n=n*n%p,k>>=1)
        if(k&1) res=res*n%p;
    return res;
}
signed main()
{
    p=read(),b=read(),n=read();
    int t=sqrt(p); if(t*t<p) t++;
    for(int i=0;i<=t;i++) mp[n*qpow(b,i)%p]=i;
    for(int i=1;i<=t;i++)
    {
        if(mp[qpow(b,t*i)])
        {
            printf("%lld\n",t*i-mp[qpow(b,t*i)]); 
            return 0;
        }
    }
    printf("no solution\n");
    return 0;
}
    

exBSGS

const int P=1e7-9;
const int N=1e7+5;
struct hsh{
    int w,val,nxt;
}e[N];
int head[N],tt;
void ins(int x,int val)
{
    for(int i=head[x%P];i;i=e[i].nxt) if(e[i].w==x) {e[i].val=val;return;}
    e[++tt]={x,val,head[x%P]};head[x%P]=tt;
}
int find(int x)
{
    for(int i=head[x%P];i;i=e[i].nxt) if(e[i].w==x) return e[i].val;
    return 0;
}
int BSGS(int a,int n,int p,int ad)
{
    int t=ceil(sqrt(p)),s=1;
    for(int i=1;i<=t;i++) s=1ll*s*a%p,ins(1ll*s*n%p,i);
    int qwq=s;s=ad;
    for(int i=0;i<=t;i++,s=1ll*s*qwq%p)
    {
        if(find(s)&&1ll*i*t-find(s)>0) 
        {
            int res=1ll*i*t-find(s),ss=1;tt=0;
            for(int i=1;i<=t;i++) ss=1ll*ss*a%p,head[(1ll*ss*n%p)%P]=0;
            return res;
        }
    }
    s=1;tt=0;
    for(int i=1;i<=t;i++) s=1ll*s*a%p,head[(1ll*s*n%p)%P]=0;
    return -1;
}
int exBSGS(int a,int n,int p)
{
    a%=p,n%=p;
    if(n==1||p==1) return 0;
    int cnt=0,ad=1;
    while("qwq")
    {
        int d=__gcd(a,p);
        if(d==1) break;
        if(n%d) return -1;
        cnt++;n/=d,p/=d;
        ad=(1ll*ad*a/d)%p;
        if(ad==n) return cnt;
    }
    int ans=BSGS(a,n,p,ad);
    return ans==-1?-1:ans+cnt;
}
signed main()
{
    while("pap")
    {
        int a=read(),p=read(),n=read();
        if(!a) return 0;
        int ans=exBSGS(a,n,p);
        if(ans==-1) printf("No Solution\n");
        else printf("%d\n",ans);
    }
    return 0;
}

类欧几里得

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int mod=998244353,inv2=499122177,inv6=166374059;
int T,n,a,b,c;
struct node{
    int f=0,g=0,h=0;
};
node solve(int a,int b,int c,int n)
{
    node d;
    if(!a)
    {
        d.f=(b/c)*(n+1)%mod;
        d.g=n*(n+1)%mod*inv2%mod*(b/c)%mod;
        d.h=(b/c)*(b/c)%mod*(n+1)%mod;
    }
    else if(a>=c||b>=c)
    {
        node q=solve(a%c,b%c,c,n);
        d.f=((n*(n+1)%mod*inv2%mod*(a/c)%mod+(n+1)*(b/c)%mod+q.f)+mod)%mod;
        d.g=((a/c)*n%mod*(n+1)%mod*(2*n+1)%mod*inv6%mod+(b/c)*n%mod*(n+1)%mod*inv2%mod+q.g)%mod;
        d.h=(2*(b/c)%mod*q.f%mod+2*(a/c)%mod*q.g%mod+(a/c)*(a/c)%mod*n%mod*(n+1)%mod*(2*n+1)%mod*inv6%mod+(b/c)*(b/c)%mod*(n+1)%mod+(a/c)*(b/c)%mod*n%mod*(n+1)%mod+q.h)%mod;
    }
    else
    {
        int m=(a*n+b)/c;
        node q=solve(c,c-b-1,a,m-1);
        d.f=(n*m%mod-q.f+mod)%mod;
        d.g=(((m*n%mod*(n+1)%mod-q.h-q.f)%mod)+mod)%mod*inv2%mod;
        d.h=((n*m%mod*(m+1)%mod-2*q.g%mod-2*q.f%mod-d.f)%mod+mod)%mod;
    }
    //cout<<a<<" "<<b<<" "<<c<<" "<<n<<" "<<d.f<<" "<<d.g<<" "<<d.h<<endl; 
    return d;
}
signed main()
{
    scanf("%lld",&T); 
    while(T--)
    {
        scanf("%lld%lld%lld%lld",&n,&a,&b,&c);
        node ans=solve(a,b,c,n);
        cout<<ans.f%mod<<" "<<ans.h%mod<<" "<<ans.g%mod<<endl;
    }
    return 0;
}

筛法

Eratosthenes 筛

bool flag[N];
void Eratosthenes(int n)
{
    for(int i=2;i<=n;i++)
    {
        if(flag[i])continue;
        for(int j=2;j*i<=n;j++) flag[j*i]=1;
    }
}

Euler 筛

for(int i=2;i<=n;i++)
{
    if(!flag[i]) p[++cnt]=i;
    for(int j=1;j<=cnt&&i*p[j]<=n;j++) 
    {
        flag[i*p[j]]=1;
        if(!i%p[j]) break;
    }
}

线性筛欧拉函数

phi[1]=1;
for(int i=2;i<=n;i++)
{
    if(!flag[i]) {p[++cnt]=i;phi[i]=i-1;}
    for(int j=1;j<=cnt&&i*p[j]<=n;j++)
    {
        flag[i*p[j]]=1;
        if(!(i%p[j])) {phi[i*p[j]]=phi[i]*p[j];break;}
        else phi[i*p[j]]=phi[i]*(p[j]-1);
    }
}

线性筛莫比乌斯函数

mu[1]=1;
for(int i=2;i<=mx;i++)
{
    if(!flag[i]) p[++cnt]=i,mu[i]=-1;
    for(int j=1;j<=cnt&&i*p[j]<=mx;j++)
    {
        flag[i*p[j]]=1;
        if(i%p[j]) mu[i*p[j]]=mu[i]*mu[p[j]];
        else {mu[i*p[j]]=0;break;}
    }
}

杜教筛

int getmu(int n)
{
    if(n<=5e6) return mu[n];
    else if(mpmu[n]) return mpmu[n];
    int res=1;
    for(int l=2,r;l<=n;l=r+1)
    {
        r=min(n,n/(n/l));
        res-=(r-l+1)*getmu(n/l);
    }
    return mpmu[n]=res;
}
int getphi(int n)
{
    if(n<=5e6) return phi[n];
    else if(mpphi[n]) return mpphi[n];
    int res=(n+1)*n/2;
    for(int l=2,r;l<=n;l=r+1)
    {
        r=min(n,n/(n/l));
        res-=(r-l+1)*getphi(n/l);
    }
    return mpphi[n]=res;
}

多项式

FFT

递归实现(常数较大,慎用)

void FFT(int limit,Complex a[],int op)
{
    if(limit==1) return;
    Complex a1[(limit>>1)+5],a2[(limit>>1)+5];
    for(int i=0;i<=limit;i+=2) a1[i>>1]=a[i],a2[i>>1]=a[i+1];
    FFT(limit>>1,a1,op),FFT(limit>>1,a2,op);
    Complex Wn={cos(2.0*pai/limit),sin(2.0*pai/limit)*op},w={1,0};
    for(int i=0;i<(limit>>1);i++,w=w*Wn)
    {
        a[i]=a1[i]+w*a2[i];
        a[i+(limit>>1)]=a1[i]-w*a2[i];
    }
}
int main()
{
    n=read(),m=read();
    for(int i=0;i<=n;i++) a[i].x=read();
    for(int i=0;i<=m;i++) b[i].x=read();
    int w=1;while(w<=m+n) w<<=1;
    FFT(w,a,1),FFT(w,b,1);
    for(int i=0;i<=w;i++) a[i]=a[i]*b[i];
    FFT(w,a,-1);
    for(int i=0;i<=n+m;i++) printf("%d ",(int)(a[i].x/w+0.5));
    return 0;
}

迭代实现

const int N=4e6+5;
const double pi=acos(-1);
int n,m,limit=1;
struct Complex {double x,y;}a[N],b[N];
il Complex operator +(Complex a,Complex b) {return {a.x+b.x,a.y+b.y};}
il Complex operator -(Complex a,Complex b) {return {a.x-b.x,a.y-b.y};}
il Complex operator *(Complex a,Complex b) {return {a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x};}
int to[N];
void FFT(Complex *a,int tp)
{
    for(int i=0;i<limit;i++) if(i<to[i]) swap(a[i],a[to[i]]);
    for(int len=1;len<limit;len<<=1)
    {
        Complex Wn={cos(pi/len),sin(pi/len)*tp};
        for(int i=0;i<limit;i+=(len<<1))
        {
            Complex w={1,0};
            for(int j=0;j<len;j++,w=w*Wn)
            {
                Complex x=a[i+j],y=w*a[i+len+j];
                a[i+j]=x+y,a[i+len+j]=x-y;
            }
        }
    }
}
int main()
{
    n=read(),m=read();
    for(int i=0;i<=n;i++) a[i].x=read();
    for(int i=0;i<=m;i++) b[i].x=read();
    int k=0; while(limit<=n+m) limit<<=1,k++;
    for(int i=0;i<limit;i++) to[i]=(to[i>>1]>>1)|((i&1)<<(k-1));
    FFT(a,1),FFT(b,1);
    for(int i=0;i<limit;i++) a[i]=a[i]*b[i];
    FFT(a,-1);
    for(int i=0;i<=n+m;i++) printf("%d ",(int)(a[i].x/limit+0.5));
    return 0;
}

NTT

#define int long long
const int N=4e6+5,mod=998244353;
il int qpow(int n,int k=mod-2)
{
    int res=1;
    for(;k;n=n*n%mod,k>>=1) if(k&1) res=res*n%mod;
    return res;
}
int n,m,a[N],b[N],inv=qpow(3),limit=1,to[N];
il void NTT(int *a,int tp)
{
    for(int i=0;i<limit;i++) if(i<to[i]) swap(a[i],a[to[i]]);
    for(int len=1;len<limit;len<<=1)
    {
        int Wn=qpow(tp>0?3:inv,(mod-1)/(len<<1));
        for(int i=0;i<limit;i+=(len<<1))
            for(int j=0,w=1;j<len;j++,w=w*Wn%mod)
            {
                int x=a[i+j],y=w*a[i+len+j]%mod;
                a[i+j]=(x+y)%mod,a[i+len+j]=(x-y+mod)%mod;
            }
    }
}
signed main()
{
    n=read(),m=read();
    for(int i=0;i<=n;i++) a[i]=read();
    for(int i=0;i<=m;i++) b[i]=read();
    int k=0; while(limit<=m+n) limit<<=1,k++;
    for(int i=0;i<limit;i++) to[i]=(to[i>>1]>>1)|((i&1)<<(k-1));
    NTT(a,1),NTT(b,1);
    for(int i=0;i<limit;i++) a[i]=a[i]*b[i]%mod;
    NTT(a,-1);
    for(int i=0;i<=n+m;i++) printf("%lld ",a[i]*qpow(limit)%mod);
    return 0;
}

FWT

void Or(int *a,int tp)
{
    for(int len=1;len<(1<<n);len<<=1)
        for(int i=0;i<(1<<n);i+=(len<<1))
            for(int j=0;j<len;j++) add(a[i+j+len],a[i+j]*tp);
}
void And(int *a,int tp)
{
    for(int len=1;len<(1<<n);len<<=1)
        for(int i=0;i<(1<<n);i+=(len<<1))
            for(int j=0;j<len;j++) add(a[i+j],a[i+j+len]*tp);
}
void Xor(int *a,int tp)
{
    for(int len=1;len<(1<<n);len<<=1)
        for(int i=0;i<(1<<n);i+=(len<<1))
            for(int j=0;j<len;j++)
            {
                int x=a[i+j],y=a[i+j+len];
                a[i+j]=(x+y)*tp%mod,a[i+j+len]=(x-y+mod)%mod*tp%mod;
            }
}

数据结构

路径压缩并查集

int find(int x) {return fa[x]==x?x:fa[x]=find(fa[x]);}
il void merge(int x,int y)
{
    if((x=find(x))==(y=find(y))) return;
    fa[x]=y;
}

单调栈

for(int i=1;i<=n;i++) scanf("%d",&a[i]);
q.push(n);
for(int i=n-1;i;i--)
{
    //cout<<i<<endl;
    if(!q.empty()) 
    {
        while(!q.empty()&&a[i]>=a[q.top()]) q.pop();
        if(!q.empty()) ans[i]=q.top();
    }
    q.push(i);
}
for(int i=1;i<=n;i++) cout<<ans[i]<<" ";

单调队列

求的是区间最小值,最大值同理

st=1,ed=0;
for(int i=1;i<=n;i++)
{
    while(st<=ed&&q[st]<=i-k) st++;
    while(st<=ed&&a[q[ed]]>a[i]) ed--;
    q[++ed]=i;
    if(i>=k) printf("%d ",a[q[st]]);
}
printf("\n");

ST 表

for(int i=1;i<=n;i++) a[i]=read(),st[0][i]=a[i];
    for(int i=1;i<=__lg(n);i++)
        for(int j=1;j<=n-(1<<i)+1;j++) st[i][j]=max(st[i-1][j],st[i-1][j+(1<<i-1)]);
while(m--)
{
    int l=read(),r=read();
    int len=__lg(r-l+1);
    printf("%d\n",max(st[len][l],st[len][r-(1<<len)+1]));
}

树状数组

单点加区间求和的经典应用

struct BIT
{
    int tr[N];
    il void add(int x,int k) {for(;x<=n;x+=x&(-x)) tr[x]+=k;}
    il int query(int x) {int res=0;for(;x;x-=x&(-x)) res+=tr[x];return res;}
    il int ask(int l,int r) {return query(r)-query(l-1);}
}tr;

区间加单点求和

struct BIT
{
    int tr[N];
    il void modify(int x,int k) {for(;x<=n;x+=x&(-x)) tr[x]+=k;}
    il void add(int l,int r,int k) {modify(l,k),modify(r+1,-k);} 
    il int query(int x) {int res=0;for(;x;x-=x&(-x)) res+=tr[x];return res;}
}tr;

线段树相关

线段树

区间加区间求和

int tr[N<<2],lz[N<<2];
#define ls (now<<1)
#define rs (now<<1|1)
#define mid (l+r>>1)
il void pushup(int now) {tr[now]=tr[ls]+tr[rs];}
il void pushdown(int now,int l,int r)
{
    tr[ls]+=lz[now]*(mid-l+1),tr[rs]+=lz[now]*(r-mid);
    lz[ls]+=lz[now],lz[rs]+=lz[now];
    lz[now]=0;
}
void build(int now,int l,int r)
{
    if(l==r) {tr[now]=a[l];return;}
    build(ls,l,mid),build(rs,mid+1,r);
    pushup(now);
}
void modify(int now,int l,int r,int ml,int mr,int k)
{
    if(l==ml&&r==mr) {tr[now]+=(r-l+1)*k,lz[now]+=k;return;}
    pushdown(now,l,r);
    if(mr<=mid) modify(ls,l,mid,ml,mr,k);
    else if(ml>mid) modify(rs,mid+1,r,ml,mr,k);
    else modify(ls,l,mid,ml,mid,k),modify(rs,mid+1,r,mid+1,mr,k);
    pushup(now);
}
int query(int now,int l,int r,int ml,int mr)
{
    if(l==ml&&r==mr) return tr[now];
    pushdown(now,l,r);
    if(mr<=mid) return query(ls,l,mid,ml,mr);
    else if(ml>mid) return query(rs,mid+1,r,ml,mr);
    else return query(ls,l,mid,ml,mid)+query(rs,mid+1,r,mid+1,mr);
}

同上,但是标记永久化版

int tr[N<<2],lz[N<<2];
void build(int now,int l,int r)
{
    if(l==r) {tr[now]=a[l];return;}
    build(ls,l,mid),build(rs,mid+1,r);
    tr[now]=tr[ls]+tr[rs];
}
void modify(int now,int l,int r,int ml,int mr,int k)
{
    tr[now]+=(mr-ml+1)*k;
    if(l==ml&&r==mr) {lz[now]+=k;return;}
    if(mr<=mid) modify(ls,l,mid,ml,mr,k);
    else if(ml>mid) modify(rs,mid+1,r,ml,mr,k);
    else modify(ls,l,mid,ml,mid,k),modify(rs,mid+1,r,mid+1,mr,k);
}
int query(int now,int l,int r,int ml,int mr)
{
    if(l==ml&&r==mr) return tr[now];
    int res=lz[now]*(mr-ml+1);
    if(mr<=mid) return res+query(ls,l,mid,ml,mr);
    else if(ml>mid) return res+query(rs,mid+1,r,ml,mr);
    else return res+query(ls,l,mid,ml,mid)+query(rs,mid+1,r,mid+1,mr);
}

区间加区间乘区间求和(线段树 2)

int tr[N<<2],lza[N<<2],lzm[N<<2];
#define ls (now<<1)
#define rs (now<<1|1)
#define mid (l+r>>1)
il void add(int &x,int y) {x+=y;x%=mod;}
il void pushup(int now) {tr[now]=(tr[ls]+tr[rs])%mod;}
il void pushdown(int now,int l,int r)
{
    (tr[ls]*=lzm[now])%=mod,(tr[rs]*=lzm[now])%=mod;
    (lzm[ls]*=lzm[now])%=mod,(lzm[rs]*=lzm[now])%=mod;
    (lza[ls]*=lzm[now])%=mod,(lza[rs]*=lzm[now])%=mod;
    lzm[now]=1;

    add(tr[ls],(mid-l+1)*lza[now]%mod),add(tr[rs],(r-mid)*lza[now]%mod);
    add(lza[ls],lza[now]),add(lza[rs],lza[now]);
    lza[now]=0;
}
il void build(int now,int l,int r)
{
    lzm[now]=1;
    if(l==r) {tr[now]=a[l];return;}
    build(ls,l,mid),build(rs,mid+1,r);
    pushup(now);
}
void modify1(int now,int l,int r,int ml,int mr,int k)
{
    if(l==ml&&r==mr) {(tr[now]*=k)%=mod,(lzm[now]*=k)%=mod,(lza[now]*=k)%=mod;return;}
    pushdown(now,l,r);
    if(mr<=mid) modify1(ls,l,mid,ml,mr,k);
    else if(ml>mid) modify1(rs,mid+1,r,ml,mr,k);
    else modify1(ls,l,mid,ml,mid,k),modify1(rs,mid+1,r,mid+1,mr,k);
    pushup(now);
}
void modify2(int now,int l,int r,int ml,int mr,int k)
{
    if(l==ml&&r==mr) {add(tr[now],(r-l+1)*k%mod),add(lza[now],k);return;}
    pushdown(now,l,r);
    if(mr<=mid) modify2(ls,l,mid,ml,mr,k);
    else if(ml>mid) modify2(rs,mid+1,r,ml,mr,k);
    else modify2(ls,l,mid,ml,mid,k),modify2(rs,mid+1,r,mid+1,mr,k);
    pushup(now);
}
int query(int now,int l,int r,int ml,int mr)
{
    if(l==ml&&r==mr) return tr[now];
    pushdown(now,l,r);
    if(mr<=mid) return query(ls,l,mid,ml,mr);
    else if(ml>mid) return query(rs,mid+1,r,ml,mr);
    else return (query(ls,l,mid,ml,mid)+query(rs,mid+1,r,mid+1,mr))%mod;
}

主席树

#include<bits/stdc++.h>
#define ls (tr[now].l)
#define rs (tr[now].r)
using namespace std;
const int N=1e6+5;
int n,m,cnt;
int a[N],rt[N];
struct node{
    int l,r,v;
}tr[N<<5];
int add(int now)
{
    tr[++cnt]=tr[now];
    return cnt;
}
int build(int now,int l,int r)
{
    now=++cnt;
    if(l==r)
    {
        tr[now].v=a[l];
        return now;
    }
    int mid=(l+r)>>1;
    tr[now].l=build(ls,l,mid);
    tr[now].r=build(rs,mid+1,r);
    return now;
}
int modify(int now,int l,int r,int x,int k)
{
    now=add(now);
    if(l==r)
    {
        tr[now].v=k;
        return now;
    }
    int mid=(l+r)>>1;
    if(x<=mid) tr[now].l=modify(ls,l,mid,x,k);
    else tr[now].r=modify(rs,mid+1,r,x,k);
    return now;
}
int query(int now,int l,int r,int x)
{
    if(l==r) return tr[now].v;
    int mid=(l+r)>>1;
    if(x<=mid) return query(ls,l,mid,x);
    else return query(rs,mid+1,r,x);
}
signed main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    rt[0]=build(0,1,n);
    for(int i=1;i<=m;i++)
    {
        int v,op,x,k;
        scanf("%d%d%d",&v,&op,&x);
        if(op==1)
        {
            scanf("%d",&k);
            rt[i]=modify(rt[v],1,n,x,k);
        }
        else
        {
            cout<<query(rt[v],1,n,x)<<endl;
            rt[i]=rt[v];
        }
    }
    return 0;
}

可持久化权值线段树(主席树 2)

求的是静态区间 \(k\) 小值。

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+5;
int n,m,a[N],t[N],rt[N],cnt;
struct node{
    int l,r,w;
}tr[N<<5];
int add(int now)
{
    tr[++cnt]=tr[now];
    return cnt;
}
int build(int now,int l,int r)
{
    now=++cnt;
    if(l==r) return now;
    int mid=(l+r)>>1;
    tr[now].l=build(tr[now].l,l,mid);
    tr[now].r=build(tr[now].r,mid+1,r);
    return now;
}
int modify(int now,int l,int r,int x)
{
    now=add(now);
    if(l==r)
    {
        tr[now].w++;
        return now;
    }
    tr[now].w++;
    int mid=(l+r)>>1;
    if(x<=mid) tr[now].l=modify(tr[now].l,l,mid,x);
    else tr[now].r=modify(tr[now].r,mid+1,r,x);
    return now;
}
int query(int vl,int vr,int l,int r,int x)
{
    if(l==r) return l;
    int mid=(l+r)>>1;
    int k=tr[tr[vr].l].w-tr[tr[vl].l].w;
    if(k>=x) return query(tr[vl].l,tr[vr].l,l,mid,x);
    else return query(tr[vl].r,tr[vr].r,mid+1,r,x-k);
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) {scanf("%d",&a[i]);t[i]=a[i];}
    sort(t+1,t+n+1);
    
    int ll=unique(t+1,t+n+1)-t-1;
    rt[0]=build(0,1,ll);
    for(int i=1;i<=n;i++)
    {
        a[i]=lower_bound(t+1,t+ll+1,a[i])-t;
        rt[i]=modify(rt[i-1],1,ll,a[i]);
    }
    for(int i=1;i<=m;i++)
    {
        int l,r,k;
        scanf("%d%d%d",&l,&r,&k);
        cout<<t[query(rt[l-1],rt[r],1,ll,k)]<<endl;
    }
    return 0;
}
    

线段树合并

#include<bits/stdc++.h>
using namespace std;
const int N=5e6+5;
int x[N],y[N],z[N];
int n,m,head[N],cnt,mx,rt[N],tot,ans[N];
int sum[N],dep[N],fa[N],son[N],top[N];
struct node{
    int nxt,to;
}e[N];
struct node1{
    int tim,mx,l,r;
}tr[N];
void add(int u,int v){
    e[++cnt].to=v;e[cnt].nxt=head[u];head[u]=cnt;
}
void dfs1(int x,int f)
{
    dep[x]=dep[f]+1;fa[x]=f;sum[x]=1;
    for(int i=head[x];i;i=e[i].nxt)
    {
        int v=e[i].to;
        if(v==f) continue;
        dfs1(v,x);
        if(sum[v]>sum[son[x]]) son[x]=v;
        sum[x]+=sum[v];
    }
}
void dfs2(int x)
{
    if(son[fa[x]]==x) top[x]=top[fa[x]];
    else top[x]=x;
    for(int i=head[x];i;i=e[i].nxt)
    {
        int v=e[i].to;
        if(v==fa[x]) continue;
        dfs2(v);
    }
}
int lca(int x,int y)
{
    while(top[x]!=top[y])
    {
        if(dep[top[x]]<dep[top[y]]) swap(x,y);
        x=fa[top[x]];
    }
    if(dep[x]<dep[y]) return x;
    else return y;
}
int modify(int now,int l,int r,int x,int k)
{
    if(!now) now=++tot;
    if(l==r)
    {
        tr[now].tim+=k;
        tr[now].mx=x;
        //cout<<"qwq "<<x<<" "<<l<<" "<<r<<endl;
        return now;
    }
    int mid=(l+r)>>1;
    if(x<=mid) tr[now].l=modify(tr[now].l,l,mid,x,k);
    else tr[now].r=modify(tr[now].r,mid+1,r,x,k);
    if(tr[tr[now].l].tim>=tr[tr[now].r].tim) {tr[now].tim=tr[tr[now].l].tim;tr[now].mx=tr[tr[now].l].mx;}
    else {tr[now].tim=tr[tr[now].r].tim;tr[now].mx=tr[tr[now].r].mx;}
    return now;
}
int merge(int a,int b,int l,int r)
{
    if((!a)) return b;if((!b)) return a;
    int mid=(l+r)>>1;
    if(l==r)
    {
        tr[a].tim+=tr[b].tim;tr[a].mx=l;
        return a;
    }
    tr[a].l=merge(tr[a].l,tr[b].l,l,mid);
    tr[a].r=merge(tr[a].r,tr[b].r,mid+1,r);
    if(tr[tr[a].l].tim>=tr[tr[a].r].tim) {tr[a].tim=tr[tr[a].l].tim;tr[a].mx=tr[tr[a].l].mx;}
    else {tr[a].tim=tr[tr[a].r].tim;tr[a].mx=tr[tr[a].r].mx;}
    return a;
}
void dfs3(int x)
{
    for(int i=head[x];i;i=e[i].nxt)
    {
        int v=e[i].to;
        if(v==fa[x]) continue;
        dfs3(v);
        rt[x]=merge(rt[x],rt[v],1,mx);
    }
    if(tr[rt[x]].tim) ans[x]=tr[rt[x]].mx;
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1,u,v;i<n;i++)
    {
        scanf("%d%d",&u,&v);
        add(u,v);add(v,u);
    }
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d%d",&x[i],&y[i],&z[i]);
        mx=max(mx,z[i]);
    }
    dfs1(1,0);dfs2(1);
    //for(int i=1;i<=n;i++) cout<<top[i]<<endl;
    for(int i=1;i<=m;i++)
    {
        int l=lca(x[i],y[i]);
        //cout<<l<<" "<<x[i]<<" "<<y[i]<<endl;
        rt[x[i]]=modify(rt[x[i]],1,mx,z[i],1);
        rt[y[i]]=modify(rt[y[i]],1,mx,z[i],1);
        rt[l]=modify(rt[l],1,mx,z[i],-1);
        if(fa[l]) rt[fa[l]]=modify(rt[fa[l]],1,mx,z[i],-1);
    }
    dfs3(1);
    for(int i=1;i<=n;i++) cout<<ans[i]<<"\n";
    return 0;
}

李超线段树

#include<bits/stdc++.h>
#define ls (now<<1)
#define rs (now<<1|1) 
using namespace std;
typedef double db;
const int N=1e5+5; 
const db eps=1e-9;
int n,lastans=0,cnt;
int tr[N<<2],ans;
db maxn;
struct node {db k,b;}a[N];
db gety(int id,db x){
    if(id==0) return 0;
    return a[id].k*x+a[id].b;
}
int readx(int x) {return (x+lastans-1)%39989+1;}
int ready(int x) {return (x+lastans-1)%1000000000+1;}
void modify(int now,int l,int r,int ml,int mr,int id)
{
    int mid=(l+r)>>1;
    if(l==ml&&r==mr)
    {
        int trw=tr[now];
        if(gety(id,mid)>gety(tr[now],mid)) tr[now]=id;
        if(gety(id,l)-gety(trw,l)>-eps&&gety(id,r)-gety(trw,r)>-eps) return;
        else if(gety(id,l)-gety(trw,l)<eps&&gety(id,r)-gety(trw,r)<eps) return;
        if(gety(id,mid)>gety(trw,mid)) {modify(ls,l,mid,ml,mid,trw);modify(rs,mid+1,r,mid+1,mr,trw);}
        else {modify(ls,l,mid,ml,mid,id);modify(rs,mid+1,r,mid+1,mr,id);}
    }
    if(mr<=mid) modify(ls,l,mid,ml,mr,id);
    else if(ml>mid) modify(rs,mid+1,r,ml,mr,id);
    else {modify(ls,l,mid,ml,mid,id);modify(rs,mid+1,r,mid+1,mr,id);}
}
void query(int now,int l,int r,int x)
{
    int mid=(l+r)>>1;
    if(gety(tr[now],x)>maxn||(gety(tr[now],x)==maxn&&tr[now]<ans)) ans=tr[now],maxn=gety(tr[now],x);
    if(l==r) return;
    if(x<=mid) query(ls,l,mid,x);
    else query(rs,mid+1,r,x);
}
int main()
{
    scanf("%d",&n);
    for(int i=1,op,xa,ya,xb,yb;i<=n;i++) 
    {
        scanf("%d",&op);
        if(op==0)
        {
            scanf("%d",&xa);xa=readx(xa);
            maxn=0.0,ans=0;
            query(1,1,40000,xa);
            cout<<ans<<endl;
            lastans=ans;
        }
        else
        {
            scanf("%d%d%d%d",&xa,&ya,&xb,&yb);
            xa=readx(xa);xb=readx(xb);ya=ready(ya);yb=ready(yb);
            if(xa>xb) {swap(xa,xb);swap(ya,yb);}
            db k=0.0,b=0.0;
            if(xa==xb) k=0.0,b=yb;
            else 
            {
                k=(db)(yb-ya)/(db)(xb-xa);
                b=(db)yb-k*(db)xb;
            }
            a[++cnt]={k,b};
            modify(1,1,40000,xa,xb,cnt); 
        }
    }
    return 0;
}    

哈夫曼树

#include<bits/stdc++.h>
#define int long long
#define pii pair<long long,long long>
#define fi first
#define se second
using namespace std;
const int N=1e5+5;
int n,k,w[N],ans;
priority_queue<pii,vector<pii>,greater<pii> > q;
signed main()
{
    scanf("%lld%lld",&n,&k);
    for(int i=1;i<=n;i++)
    {
        scanf("%lld",&w[i]);
        q.push(pii(w[i],0)); 
    }
    while((q.size()-1)%(k-1)) q.push(pii(0,0)); 
    while(q.size()>1)
    {
        int sum=0,maxn=0;
        for(int i=1;i<=k;i++)
        {
            if(q.empty()) break;
            sum+=q.top().fi;
            maxn=max(maxn,q.top().se);
            q.pop();
        }
        ans+=sum;
        q.push(pii(sum,maxn+1));
    }
    cout<<ans<<"\n"<<q.top().se<<endl;
    return 0;
}
            

笛卡尔树

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1e7+5;
inline int read()
{
    int xr=0;char cr;
    cr=getchar();
    while(cr<'0'||cr>'9') cr=getchar();
    while(cr>='0'&&cr<='9') xr=(xr<<3)+(xr<<1)+(cr^48),cr=getchar();
    return xr;
}
struct node{
    int l,r;
}tr[N];
int n,a[N],w[N];
int q[N],st;
inline void build()
{
    for(int i=1;i<=n;i++)
    {
        int x=a[i],now=0;
        while(st&&a[q[st]]>x) now=q[st],st--;
        if(st) tr[q[st]].r=i;
        if(now) tr[i].l=now;
        q[++st]=i;
    }
}
signed main()
{
    n=read();
    for(int i=1;i<=n;i++) a[i]=read(),w[a[i]]=i;
    build(); 
    ll ansl=0,ansr=0;
    for(int i=1;i<=n;i++)
    {
        ansl^=1ll*i*(tr[i].l+1);
        ansr^=1ll*i*(tr[i].r+1);
        //cout<<tr[i].l<<" "<<tr[i].r<<endl;
    }
    printf("%lld %lld",ansl,ansr);
    //cout<<ansl<<" "<<ansr<<endl;
    return 0;
}

左偏树(可并堆)

#define ls(x) tr[(x)].l
#define rs(x) tr[(x)].r
const int N=1e5+5;
int n,m;
struct node{
    int val,id,dist;
    int fa,l,r;
}tr[N];
int find(int x)
{
    if(tr[x].fa==x) return x;
    else return tr[x].fa=find(tr[x].fa);
}
int merge(int x,int y)
{
    if(!x||!y) return x+y;
    if(tr[x].val>tr[y].val||(tr[x].val==tr[y].val&&tr[x].id>tr[y].id)) swap(x,y);
    rs(x)=merge(rs(x),y);
    if(tr[ls(x)].dist<tr[rs(x)].dist) swap(ls(x),rs(x));
    tr[x].dist=tr[rs(x)].dist+1;
    return x;
}
bool flag[N];
int main()
{
    n=read(),m=read();
    for(int i=1;i<=n;i++) tr[i]={read(),i,1,i,0,0};
    while(m--)
    {
        int op=read(),x=read();
        if(op==1)
        {
            int y=read();
            if(flag[x]||flag[y]) continue;
            x=find(x),y=find(y);
            if(x!=y) tr[x].fa=tr[y].fa=merge(x,y);
        }
        else
        {
            if(flag[x]) {printf("-1\n");continue;}
            x=find(x),flag[x]=1;
            printf("%d\n",tr[x].val);
            tr[x].fa=tr[ls(x)].fa=tr[rs(x)].fa=merge(ls(x),rs(x));
        }
    }
    return 0;
}

平衡树

Splay

const int N=1e5+5;
struct tree
{
    int s[2],siz,fa,key;
    tree(){s[0]=s[1]=siz=fa=key=0;}
}tr[N];
#define ls(x) tr[(x)].s[0]
#define rs(x) tr[(x)].s[1]
#define fa(x) tr[(x)].fa
int rt,idx;
il int newnode(int key) {tr[++idx].key=key,tr[idx].siz=1;return idx;}
il void maintain(int x) {tr[x].siz=tr[ls(x)].siz+tr[rs(x)].siz+1;}
il void clear(int x) {ls(x)=rs(x)=fa(x)=tr[x].siz=tr[x].key=0;}
il bool get(int x) {return x==rs(fa(x));}
il void rotate(int x)
{
    int y=fa(x),z=fa(y); int c=get(x);
    if(tr[x].s[c^1]) fa(tr[x].s[c^1])=y;
    tr[y].s[c]=tr[x].s[c^1],tr[x].s[c^1]=y,fa(y)=x,fa(x)=z;
    if(z) tr[z].s[y==tr[z].s[1]]=x; //not get(y)!
    maintain(y),maintain(x);
}
il void splay(int x)
{
    for(int f=fa(x);f=fa(x),f;rotate(x))
        if(fa(f)) rotate(get(f)==get(x)?f:x);
    rt=x;
}
il void ins(int key)
{
    int now=rt,f=0;
    while(now) f=now,now=tr[now].s[key>tr[now].key];
    now=newnode(key),fa(now)=f,tr[f].s[key>tr[f].key]=now,splay(now);
}
il void del(int key)
{
    int now=rt,p=0;
    while(tr[now].key!=key&&now) p=now,now=tr[now].s[key>tr[now].key]; 
    if(!now) {splay(p);return;}
    splay(now); int cur=ls(now);
    if(!cur) {rt=rs(now),fa(rs(now))=0,clear(now);return;} 
    while(rs(cur)) cur=rs(cur);
    rs(cur)=rs(now),fa(rs(now))=cur,fa(ls(now))=0,clear(now); 
    maintain(cur),splay(cur);
}
il int pre(int key)
{
    int now=rt,ans=0,p;
    while(now)
        if(p=now,tr[now].key>=key) now=ls(now);
        else ans=tr[now].key,now=rs(now);
    return splay(p),ans;
}
il int nxt(int key)
{
    int now=rt,ans=0,p;
    while(now)
        if(p=now,tr[now].key<=key) now=rs(now);
        else ans=tr[now].key,now=ls(now);
    return splay(p),ans;
}
il int rnk(int key)
{
    int res=1,now=rt,p;
    while(now)
        if(p=now,tr[now].key<key) res+=tr[ls(now)].siz+1,now=rs(now);
        else now=ls(now);
    return splay(p),res;
}
il int kth(int rk)
{
    int now=rt;
    while(now)
    {
        int sz=tr[ls(now)].siz+1;
        if(sz>rk) now=ls(now);
        else if(sz==rk) break;
        else rk-=sz,now=rs(now);
    }
    return splay(now),tr[now].key;
}

Splay 区间翻转

const int N=1e5+5,inf=2e9;
struct tree
{
    int s[2],siz,fa,key,lz;
    tree(){s[0]=s[1]=siz=fa=key=lz=0;}
}tr[N];
#define ls(x) tr[(x)].s[0]
#define rs(x) tr[(x)].s[1]
#define fa(x) tr[(x)].fa
int rt,idx,a[N];
il int newnode(int key) {tr[++idx].key=key,tr[idx].siz=1;return idx;}
il void maintain(int x) {tr[x].siz=tr[ls(x)].siz+tr[rs(x)].siz+1;}
il void clear(int x) {ls(x)=rs(x)=fa(x)=tr[x].siz=tr[x].key=0;}
il bool get(int x) {return x==rs(fa(x));}
il void rotate(int x)
{
    int y=fa(x),z=fa(y); int c=get(x);
    if(tr[x].s[c^1]) fa(tr[x].s[c^1])=y;
    tr[y].s[c]=tr[x].s[c^1],tr[x].s[c^1]=y,fa(y)=x,fa(x)=z;
    if(z) tr[z].s[y==tr[z].s[1]]=x; //not get(y)!
    maintain(y),maintain(x);
}
il void splay(int x,int y)
{
    for(int f=fa(x);f=fa(x),f!=y;rotate(x))
        if(fa(f)!=y) rotate(get(f)==get(x)?f:x);
    if(!y) rt=x;
}
il void pushdown(int x)
{
    if(!tr[x].lz) return;
    swap(ls(x),rs(x)),tr[ls(x)].lz^=1,tr[rs(x)].lz^=1;
    tr[x].lz=0; return;
}
il int find(int x)
{
    int now=rt; x++;
    while(now)
    {
        pushdown(now); int sz=tr[ls(now)].siz+1;
        if(sz==x) break;
        else if(sz>x) now=ls(now);
        else now=rs(now),x-=sz;
    }
    return now;
}
il void reverse(int l,int r)
{
    int x=find(l-1); splay(x,0);
    int y=find(r+1); splay(y,x);
    tr[ls(y)].lz^=1;
}
void write(int now)
{
    pushdown(now);
    if(ls(now)) write(ls(now));
    if(tr[now].key) printf("%d ",tr[now].key);
    if(rs(now)) write(rs(now));
}
int n,m;
il void build()
{
    rt=newnode(0); int now=rt;
    for(int i=1;i<=n+1;i++) 
        tr[now].siz=n+3-i,rs(now)=newnode(a[i]),fa(rs(now))=now,now=rs(now);
}
int main()
{
    n=read(),m=read();
    for(int i=1;i<=n;i++) a[i]=i;
    build();
    while(m--)
    {
        int l=read(),r=read();
        reverse(l,r);
    }
    write(rt);
    return 0;
}

FHQ Treap

#define ls(x) tr[(x)].l
#define rs(x) tr[(x)].r
const int N=1e5+5;
struct node {int l,r,key,val,siz;} tr[N];
int rt,idx,x,y,z;
il int add(int key) {tr[++idx]={0,0,key,rand(),1};return idx;}
il void upd(int x) {tr[x].siz=tr[ls(x)].siz+tr[rs(x)].siz+1;}
void split(int now,int key,int &x,int &y)
{
    if(!now) {x=y=0;return;}
    if(tr[now].key<=key) x=now,split(rs(x),key,rs(x),y),upd(x);
    else y=now,split(ls(y),key,x,ls(y)),upd(y);
}
int merge(int x,int y)
{
    if(!x||!y) return x+y;
    if(tr[x].val<tr[y].val) {rs(x)=merge(rs(x),y),upd(x);return x;}
    else {ls(y)=merge(x,ls(y)),upd(y);return y;}
}
il void ins(int key) {split(rt,key,x,y),rt=merge(merge(x,add(key)),y);}
il void del(int key)
{
    split(rt,key,y,z),split(y,key-1,x,y);
    y=merge(ls(y),rs(y)),rt=merge(merge(x,y),z);
}
il int rnk(int key)
{
    split(rt,key-1,x,y); int res=tr[x].siz+1;
    rt=merge(x,y); return res;
}
il int kth(int rk)
{
    int now=rt;
    while(now)
    {
        int sz=tr[ls(now)].siz+1;
        if(sz<rk) rk-=sz,now=rs(now);
        else if(sz==rk) return tr[now].key;
        else now=ls(now);
    }
    assert(false); return 0;
}
il int pre(int key)
{
    split(rt,key-1,x,y); int now=x;
    while(rs(now)) now=rs(now);
    rt=merge(x,y); return tr[now].key;
}
il int nxt(int key)
{
    split(rt,key,x,y); int now=y;
    while(ls(now)) now=ls(now);
    rt=merge(x,y); return tr[now].key;
}

FHQ Treap 区间翻转

#define ls(x) tr[(x)].l
#define rs(x) tr[(x)].r
const int N=1e5+5;
struct node{int l,r,val,key,siz,lz;} tr[N];
int rt,tot,x,y,z;
il void upd(int x) {tr[x].siz=tr[ls(x)].siz+tr[rs(x)].siz+1;}
il void push_down(int now)
{
    if(!tr[now].lz) return;
    tr[now].lz=0,swap(ls(now),rs(now));
    if(ls(now)) tr[ls(now)].lz^=1;
    if(rs(now)) tr[rs(now)].lz^=1;
}
void split(int now,int rk,int &x,int &y)
{
    if(!now) {x=y=0;return;}
    push_down(now);
    int qwq=tr[ls(now)].siz+1;
    if(qwq<=rk) x=now,split(rs(now),rk-qwq,rs(x),y),upd(x);
    else y=now,split(ls(now),rk,x,ls(y)),upd(y);
}
int merge(int x,int y)
{
    push_down(x),push_down(y);
    if(!x||!y) return x+y;
    if(tr[x].val<tr[y].val) {rs(x)=merge(rs(x),y),upd(x);return x;}
    else {ls(y)=merge(x,ls(y)),upd(y);return y;}
}
void print(int now)
{
    push_down(now);
    if(ls(now)) print(ls(now));
    printf("%d ",tr[now].key);
    if(rs(now)) print(rs(now));
}
void rev(int l,int r)
{
    split(rt,r,y,z),split(y,l-1,x,y);
    tr[y].lz=1;
    rt=merge(merge(x,y),z);
}
const int N=3e5+5;
struct node
{
    int key,sum,fa,lz;
    int s[2];
    node() {key=sum=fa=lz=s[0]=s[1]=0;}
}tr[N];
#define ls(x) tr[(x)].s[0]
#define rs(x) tr[(x)].s[1]
#define fa(x) tr[(x)].fa
il bool get(int x) {return rs(fa(x))==x;}
il bool isroot(int x) {return ls(fa(x))!=x&&rs(fa(x))!=x;}
il void pushup(int x) {tr[x].sum=tr[ls(x)].sum^tr[rs(x)].sum^tr[x].key;}
il void pushdown(int x)
{
    if(!tr[x].lz) return;
    swap(ls(x),rs(x)),tr[ls(x)].lz^=1,tr[rs(x)].lz^=1;
    tr[x].lz=0;
}
il void update(int x)
{
    if(!isroot(x)) update(fa(x));
    pushdown(x);
}
il void rotate(int x)
{
    int y=fa(x),z=fa(y),c=get(x);
    if(!isroot(y)) tr[z].s[get(y)]=x;
    fa(tr[x].s[c^1])=y,tr[y].s[c]=tr[x].s[c^1],tr[x].s[c^1]=y;
    fa(y)=x,fa(x)=z; pushup(y),pushup(x);
}
il void splay(int x)
{
    update(x);
    for(int f=fa(x);f=fa(x),!isroot(x);rotate(x))
        if(!isroot(f)) rotate(get(f)==get(x)?f:x);
}
il void access(int x) {for(int p=0;x;p=x,x=fa(x)) splay(x),rs(x)=p,pushup(x);}
il void makeroot(int x) {access(x),splay(x),tr[x].lz^=1;}
il int find(int x)
{
    access(x),splay(x);
    while(pushdown(x),ls(x)) x=ls(x);
    return splay(x),x;
}
il void link(int x,int y) {makeroot(x);if(find(y)!=x) fa(x)=y;}
il void split(int x,int y) {makeroot(x),access(y),splay(y);}
il void cut(int x,int y)
{
    makeroot(x);
    if(find(y)==x&&fa(y)==x&&!ls(y)) fa(y)=rs(x)=0;
}

字符串

Hash

const int p=131;
ull n,a[10005],ans;
string s;
ull hash(string x)
{
    int l=x.size();
    ull res=0;
    for(int i=0;i<=l;i++) res=res*p+x[i];
    return res;
}

Trie

struct trie{int nxt,s[26];} tr[N];
void ins(char *s)
{
    int len=strlen(s+1),now=0;
    for(int i=1;i<=len;i++)
    {
        int &to=tr[now].s[s[i]-'a'];
        if(!to) to=++tot; now=to;
    }
}

KMP

scanf("%s%s",t+1,s+1); 
n=strlen(t+1),m=strlen(s+1);
for(int now=0,i=2;i<=m;i++)
{
    while(now&&s[i]!=s[now+1]) now=nxt[now];
    if(s[i]==s[now+1]) now++;
    nxt[i]=now;
}
for(int now=0,i=1;i<=n;i++)
{
    while(now&&s[now+1]!=t[i]) now=nxt[now];
    if(s[now+1]==t[i]) now++;
    if(now==m) printf("%d\n",i-m+1);
}

AC 自动机 (ACAM)

solve 函数省略,看具体题目

char s[N];
struct trie{int nxt,s[26];} d[N];
void ins(char *s)
{
    int len=strlen(s+1),now=0;
    for(int i=1;i<=len;i++)
    {
        int &to=d[now].s[s[i]-'a'];
        if(!to) to=++tot; now=to;
    }
}
void getfail()
{
    queue<int> q;
    for(int i=0;i<26;i++) if(d[0].s[i]) q.push(d[0].s[i]);
    while(!q.empty())
    {
        int u=q.front(); q.pop();
        for(int i=0;i<26;i++)
        {
            if(!d[u].s[i]) d[u].s[i]=d[d[u].nxt].s[i];
            else d[d[u].s[i]].nxt=d[d[u].nxt].s[i],q.push(d[u].s[i]);
        }
    }
}

Manacher

#include<bits/stdc++.h>
using namespace std;
const int N=2.2e7+5;
int cnt=1,r[N],mid=1,R,maxn;
char s[N],c;
int main()
{
    s[0]='~';s[1]='#';
    c=getchar();
    while(c<'a'||c>'z') c=getchar();
    while(c>='a'&&c<='z') s[++cnt]=c,s[++cnt]='#',c=getchar();
    for(int i=1;i<=cnt;i++)
    {
        if(i<R) r[i]=min(R-i+1,r[2*mid-i]);
        while(s[i-r[i]]==s[i+r[i]]) r[i]++;
        if(i+r[i]-1>=R) R=i+r[i]-1,mid=i;
        maxn=max(maxn,r[i]-1);
    }
    cout<<maxn<<endl;
    return 0;
}
    

回文自动机 (PAM)

const int N=5e5+5;
int n,tot=1;
struct node
{
    int len,fa,dep;
    int s[26];
}d[N];
char s[N];
il int getfail(int u,int i)
{
    while(i-d[u].len-1<=0||s[i-d[u].len-1]!=s[i]) u=d[u].fa;
    return u;
}
int main()
{
    scanf("%s",s+1); n=strlen(s+1);
    d[0].fa=1,d[1].len=-1;
    int now=0,lst=0;
    for(int i=1;i<=n;i++)
    {
        s[i]=(s[i]-'a'+lst)%26+'a';
        int pos=getfail(now,i); int c=s[i]-'a';
        if(!d[pos].s[c])
        {
            d[++tot].fa=d[getfail(d[pos].fa,i)].s[c];
            d[pos].s[c]=tot,d[tot].len=d[pos].len+2;
            d[tot].dep=d[d[tot].fa].dep+1;
        }
        now=d[pos].s[c];
        printf("%d ",lst=d[now].dep);
    }
    return 0;
}

后缀数组 (SA)

int n,m,sa[N],rk[N],sum[N],tp[N];
int hgt[N];
void qsort()
{
    for(int i=1;i<=m;i++) sum[i]=0;
    for(int i=1;i<=n;i++) sum[rk[i]]++;
    for(int i=1;i<=m;i++) sum[i]+=sum[i-1];
    for(int i=n;i;i--) sa[sum[rk[tp[i]]]--]=tp[i];
}
void SA()
{
    for(int i=1;i<=n;i++) rk[i]=s[i],tp[i]=i;
    m=200,qsort();
    for(int w=1,tot=0;w<=n&&tot<n;w<<=1,m=tot) 
    {
        tot=0;
        for(int i=n-w+1;i<=n;i++) tp[++tot]=i;
        for(int i=1;i<=n;i++) 
            if(sa[i]>w) tp[++tot]=sa[i]-w;
        qsort(); swap(rk,tp);
        tot=rk[sa[1]]=1;
        for(int i=2;i<=n;i++)
            rk[sa[i]]=(tp[sa[i]]==tp[sa[i-1]]&&tp[sa[i]+w]==tp[sa[i-1]+w])?tot:++tot;
    }
}
void get_hgt()
{
    for(int i=1,now=0;i<=n;i++)
    {
        if(now) now--;
        while(s[i+now]==s[sa[rk[i]-1]+now]) now++;
        hgt[rk[i]]=now;
    }
}

后缀自动机 (SAM)

void add(int c)
{
    int p=lst,np=lst=++tot;f[tot]=1;
    d[np].len=d[p].len+1;
    for(;p&&!d[p].ch[c];p=d[p].fa) d[p].ch[c]=np;
    if(!p) d[np].fa=1;
    else
    {
        int q=d[p].ch[c];
        if(d[q].len==d[p].len+1) d[np].fa=q;
        else
        {
            int nq=++tot;
            d[nq]=d[q];d[nq].len=d[p].len+1;
            d[q].fa=d[np].fa=nq;
            for(;p&&d[p].ch[c]==q;p=d[p].fa) d[p].ch[c]=nq;
        }
    }
}

广义 SAM

离线 bfs

struct trie{int fa,c,s[26];} tr[N];
int idx=1;
il void ins(char *s) 
{
    int len=strlen(s+1),now=1;
    for(int i=1;i<=len;i++) 
    {
        int &to=tr[now].s[s[i]-'a'];
        if(!to) to=++idx,tr[to].fa=now,tr[to].c=s[i]-'a'; now=to;
    }
}
struct SAM{int fa,len,s[26];} d[N];
int tot=1;
il int insert(int c,int lst)
{
    int p=lst,np=lst=++tot; d[np].len=d[p].len+1;
    for(;p&&!d[p].s[c];p=d[p].fa) d[p].s[c]=np;
    if(!p) {d[np].fa=1;return np;}
    int q=d[p].s[c];
    if(d[q].len==d[p].len+1) {d[np].fa=q;return np;}
    int nq=++tot; d[nq]=d[q],d[nq].len=d[p].len+1;
    d[q].fa=d[np].fa=nq;
    for(;p&&d[p].s[c]==q;p=d[p].fa) d[p].s[c]=nq;
    return np;
}
int pos[N];
il void build()
{
    queue<int> q;
    for(int i=0;i<26;i++) if(tr[1].s[i]) q.push(tr[1].s[i]);
    pos[1]=1;
    while(!q.empty())
    {
        int u=q.front(); q.pop();
        pos[u]=insert(tr[u].c,pos[tr[u].fa]);
        for(int i=0;i<26;i++) if(tr[u].s[i]) q.push(tr[u].s[i]);
    }
}

在线构造

struct SAM{int fa,len,s[26];} d[N];
int tot=1,pos[N];
il int insert(int c,int lst)
{
    if(d[lst].s[c]&&d[d[lst].s[c]].len==d[lst].len+1) {return d[lst].s[c];} 
    int p=lst,np=++tot,flag=0; d[np].len=d[p].len+1;
    for(;p&&!d[p].s[c];p=d[p].fa) d[p].s[c]=np;
    if(!p) {d[np].fa=1;return np;}
    int q=d[p].s[c];
    if(d[q].len==d[p].len+1) {d[np].fa=q;return np;}
    if(p==lst) flag=1,np=0,tot--;  
    int nq=++tot; d[nq]=d[q],d[nq].len=d[p].len+1;
    d[q].fa=d[np].fa=nq;
    for(;p&&d[p].s[c]==q;p=d[p].fa) d[p].s[c]=nq;
    return flag?nq:np;  
}

计算几何

扫描线

#include<bits/stdc++.h>
#define int long long
#define ls (now<<1)
#define rs (now<<1|1)
using namespace std;
const int N=3e5+5;
int n;
struct node{
    int x,l,r,op;
}a[N];
int cnt,num,b[N],lz[N<<2];
struct node1{
    int mn,cnt,l;
}tr[N<<2];
bool cmp(node x,node y){
    return x.x<y.x;
}
void push_down(int now)
{
    tr[ls].mn+=lz[now];tr[rs].mn+=lz[now];
    lz[ls]+=lz[now];lz[rs]+=lz[now];
    lz[now]=0;
}
void build(int now,int l,int r)
{
    tr[now].l=tr[now].cnt=b[r+1]-b[l];
    if(l==r) return;
    int mid=(l+r)>>1;
    build(ls,l,mid);build(rs,mid+1,r);
}
void modify(int now,int l,int r,int ml,int mr,int op)
{
    if(l==ml&&r==mr) tr[now].mn+=op,lz[now]+=op;return;}
    int mid=(l+r)>>1;
    push_down(now);
    if(mr<=mid) modify(ls,l,mid,ml,mr,op);
    else if(ml>mid) modify(rs,mid+1,r,ml,mr,op);
    else
    {
        modify(ls,l,mid,ml,mid,op);
        modify(rs,mid+1,r,mid+1,mr,op);
    }
    tr[now].mn=min(tr[ls].mn,tr[rs].mn);
    tr[now].cnt=0;
    if(tr[ls].mn==tr[now].mn) tr[now].cnt+=tr[ls].cnt;
    if(tr[rs].mn==tr[now].mn) tr[now].cnt+=tr[rs].cnt;
}
int query(int now,int l,int r,int ml,int mr)
{
    if(tr[now].mn!=0) return tr[now].l;
    else return tr[now].l-tr[now].cnt;
}
signed main()
{
    scanf("%lld",&n);
    for(int i=1,xa,xb,ya,yb;i<=n;i++)
    {
        scanf("%lld%lld%lld%lld",&xa,&ya,&xb,&yb);
        a[++cnt].x=xa,a[cnt].l=ya,a[cnt].r=yb,a[cnt].op=1;
        a[++cnt].x=xb,a[cnt].l=ya,a[cnt].r=yb,a[cnt].op=-1;
        b[++num]=ya,b[++num]=yb;
    }
    sort(b+1,b+num+1);
    int len=unique(b+1,b+num+1)-b-1;
    for(int i=1;i<=cnt;i++)
    {
        a[i].l=lower_bound(b+1,b+len+1,a[i].l)-b;
        a[i].r=lower_bound(b+1,b+len+1,a[i].r)-b;
    }
    sort(a+1,a+cnt+1,cmp);
    build(1,1,len-1);
    int ans=0;
    for(int i=1;i<cnt;i++)
    {
        modify(1,1,len-1,a[i].l,a[i].r-1,a[i].op);
        ans+=query(1,1,len-1,1,len-1)*(a[i+1].x-a[i].x);
    }
    cout<<ans<<endl;
    return 0;
}

平面最近点对

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=4e5+5;
typedef double db;
int n;db ans=1e18;
struct node{
    db x,y;
}a[N],t[N];
bool cmpx(node c,node d)
{
    if(c.x==d.x) return c.y<d.y;
    else return c.x<d.x;
}
bool cmpy(node c,node d){
    return c.y<d.y;
}
db dis(node c,node d){
    return (c.x-d.x)*(c.x-d.x)+(c.y-d.y)*(c.y-d.y);
}
void solve(int l,int r)
{
    if(l==r) return;
    int mid=(l+r)>>1;
    db m=a[mid].x;
    solve(l,mid);solve(mid+1,r);
    int cnt=0;
    for(int i=l;i<=r;i++)
    {
        if(a[i].x>=m-sqrt(ans)&&a[i].x<=m+sqrt(ans)) t[++cnt]=a[i];
    }
    sort(t+1,t+cnt+1,cmpy);
    for(int i=1;i<=cnt;i++)
    {
        for(int j=i+1;j<=cnt;j++)
        {
            if(t[j].y>t[i].y+sqrt(ans)) break;
            ans=min(ans,dis(t[j],t[i]));
        }
    }
}
signed main()
{
    scanf("%lld",&n);
    for(int i=1;i<=n;i++) scanf("%lf%lf",&a[i].x,&a[i].y);
    sort(a+1,a+n+1,cmpx);
    solve(1,n);
    cout<<(long long)ans<<endl;
    return 0;
}

全家桶

typedef double db;
const db eps=1e-10;
struct V{
    db x,y;
};
#define il inline
/*向量之间运算*/ 
il bool operator ==(const V &a,const V &b) {return fabs(a.x-b.x)<=eps&&fabs(a.y-b.y)<=eps;}  
il bool operator !=(const V &a,const V &b) {return !(a==b);}

il V operator +(const V &a,const V &b) {return {a.x+b.x,a.y+b.y};}
il V operator -(const V &a,const V &b) {return {a.x-b.x,a.y-b.y};}
il V operator *(const V &a,const db &x) {return {a.x*x,a.y*x};}
il V operator *(const db &x,const V &a) {return {a.x*x,a.y*x};}
il V operator /(const V &a,const db &x) {return {a.x/x,a.y/x};}

il db operator *(const V &a,const V &b) {return a.x*b.x+a.y*b.y;} 
il db operator ^(const V &a,const V &b) {return a.x*b.y-a.y*b.x;}

il db len(const V &a) {return sqrt(a*a);}
il V  mid(const V &a,const V &b) {return {(a.x+b.x)/2,(a.y+b.y)/2};}
il V  cui(const V &a) {return {a.y,-a.x};}
il V   dw(const V &a) {return a/len(a);}

/*角度*/
il db tri_S(const V &a,const V &b,const V &c) {return fabs((a-c)^(b-c))/2;}
il db angle(const V &a,const V &b) {return acos(a*b/len(a)/len(b));}
//以下均为角 BAC. 
il bool zhi(const V &a,const V &v,const V &c) {return fabs((b-a)*(c-a))<=eps;} 
il bool dun(const V &a,const V &b,const V &c) {return (b-a)*(c-a)<-eps;}
il bool rui(const V &a,const V &b,const V &c) {return (b-a)*(c-a)>eps;}
il V turn(const V &a,db t){
    db s=sin(t),c=cos(t);
    return {a.x*c-a.y*s,a.x*s+a.y*c};
}

/*线*/
struct line{
    V d,a,b;
};
inline line trans(db a,db b,db c,db d)
{
    V dd={c-a,d-b},x={a,b},y={c,d};
    dd=dw(dd);
    return {dd,x,y};
}
inline line trans(const V &a,const V &b)
{
    V dd={b.x-a.x,b.y-a.y};dd=dw(dd);
    return {dd,a,b};
}

/*点和线的关系*/
il V cui(const V &o,const line &l) {return ((o-l.a)*l.d)*l.d+l.a;}
il V duichen(const V &o,const line &l)
{
    V qwq=cui(o,l);
    return {2*qwq.x-o.x,2*qwq.y-o.y};
}
il db dis(const V &o,const line &l,int op=0)
{
    if(op&&(dun(l.a,o,l.b)||dun(l.b,o,l.a))) return min(len(l.a-o),len(l.b-o));
    else return fabs((l.a-o)^(l.b-o))/len(l.b-l.a);
}
il bool on_line(const line &l,const V &o) {return fabs((o-l.a)^(l.b-l.a))<eps;}
il bool on_seg(const line &l,const V &o) {return fabs(len(o-l.a)+len(o-l.b)-len(l.b-l.a))<eps;}
il int pos(const line &l,const V &o)
{
    if(!on_line(l,o)) 
    {
        if((o-l.a)^l.d<-eps) return 1;//clockwise
        else return 2;//counter clockwise
    }
    if((o-l.a)*(o-l.b)<-eps) return 5;//on
    else if(len(o-l.a)>len(o-l.b)) return 3;//front
    else return 4;//back
}

/*线和线*/
//线和线
il bool gongxian(const line &a,const line &b) {return fabs(a.d^b.d)<eps;}
il bool cuizhi  (const line &a,const line &b) {return fabs(a.d*b.d)<eps;} 
il bool xdjiao(const line &u,const line &v)//拼音太长缩写了>_< 
{
    if(min(u.a.x,u.b.x)>max(v.a.x,v.b.x)+eps||max(u.a.x,u.b.x)<min(v.a.x,v.b.x)-eps) return 0;
    if(min(u.a.y,u.b.y)>max(v.a.y,v.b.y)+eps||max(u.a.y,u.b.y)<min(v.a.y,v.b.y)-eps) return 0;
    return ((u.a-v.a)^v.d)*((u.b-v.a)^v.d)<eps&&((v.a-u.a)^u.d)*((v.b-u.a)^u.d)<eps;
}
il V jiaodian(const line &u,const line &v)
{
    double k=((v.a-u.a)^v.d)/(u.d^v.d);
    return k*u.d+u.a;
}
il line pingfen(const V &a,const V &b,const V &c)//角 BAC 
{
    int d1=dw(b-a),d2=dw(c-a);
    int d=(d1+d2)/2;
    return (line){d,a,a+d};
}

/*多边形*/
il int in_poly(V *a,int n,V o)
{
    int res=0;a[n+1]=a[1];
    for(int i=1;i<=n;i++)
    {
        V u=a[i],v=a[i+1];
        if(on_seg(trans(u,v),o)) return 1;
        if(abs(u.y-v.y)<eps) continue;
        if(max(u.y,v.y)<o.y-eps) continue;
        if(min(u.y,v.y)>o.y-eps) continue;
        double x=u.x+(o.y-u.y)/(v.y-u.y)*(v.x-u.x);
        if(x<o.x) res^=1;
    }
    return res?2:0;
}
il double S(V *a,int n)
{
    db res=0;
    for(int i=1;i<=n;i++) res+=(a[i]^a[i%n+1]);
    return res/2;
}
il int is_convex(V *a,int n)
{
    a[0]=a[n],a[n+1]=a[1];
    int op=0;
    for(int i=1;i<=n;i++)
    {
        V x=a[i]-a[i-1],y=a[i+1]-a[i];
        if(abs(x^y)<eps) continue;
        int np=((x^y)>0)?1:-1;
        if(!op) op=np;
        else if(op!=np) return 0;
    }
    return 1;
}

/*凸包*/
V Q[N];int tp;
bool cmp(V a,V b)
{
    if(a.x==b.x) return a.y<b.y;
    else return a.x<b.x;
}
void andrew(V *a,int n)
{
    sort(a+1,a+n+1,cmp);
    Q[++tp]=a[1];
    for(int i=2;i<=n;Q[++tp]=a[i],i++)
        while(tp>1&&((Q[tp]-Q[tp-1])^(a[i]-Q[tp]))<eps) tp--;
    int pos=tp;
    for(int i=n-1;i;Q[++tp]=a[i],i--)
        while(tp>pos&&((Q[tp]-Q[tp-1])^(a[i]-Q[tp]))<eps) tp--;
    tp--;
}

/*旋转卡壳*/
int ans;
void find()
{
    int now=2;
    for(int i=1;i<=tp;i++)
    {
        V a=Q[i],b=Q[i%tp+1];
        while(Dis(a,b,Q[now%tp+1])>Dis(a,b,Q[now])) now=now%tp+1;
        ans=max(ans,dis(a,Q[now]));
        ans=max(ans,dis(b,Q[now]));
    }
}

/*半平面交*/
struct line
{
    V a,b,d;
    double angle;
}a[N];
line trans(V a,V b) 
{
    double res=atan2((b-a).y,(b-a).x);V d=(b-a)/len(b-a);
    return {a,b,d,res};
}
V jiaodian(line a,line b)
{
    double k=((b.a-a.a)^(b.d))/(a.d^b.d);
    return a.a+(k*a.d);
}
bool cmp(line x,line y)
{
    if(fabs(x.angle-y.angle)>eps) return x.angle<y.angle;
    else return ((y.a-x.a)^(y.b-x.a))>eps;
}
bool check(line a,line b,line c)
{
    V p=jiaodian(b,c);
    return (a.d^(p-a.a))<-eps;
}
line Q[N];
int h=1,t=0,tot;
V ans[N];
void solve()
{
    sort(a+1,a+tot+1,cmp);
    int cnt=1;
    for(int i=2;i<=tot;i++)
        if(fabs(a[i].angle-a[i-1].angle)>eps) a[++cnt]=a[i];
    tot=cnt;
    
    Q[++t]=a[1],Q[++t]=a[2];
    for(int i=3;i<=tot;i++)
    {
        while(h<t&&check(a[i],Q[t],Q[t-1])) t--;
        while(h<t&&check(a[i],Q[h],Q[h+1])) h++;
        Q[++t]=a[i];
    }
    while(h<t&&check(Q[h],Q[t],Q[t-1])) t--;
    while(h<t&&check(Q[t],Q[h],Q[h+1])) h++;
    int qwq=0;
    for(int i=h;i<t;i++) ans[++qwq]=jiaodian(Q[i],Q[i+1]);
    if(t-h>1) ans[++qwq]=jiaodian(Q[h],Q[t]);
    tot=qwq;
}
int main()
{
    int n=read();tot=0;
    for(int i=1;i<=n;i++)
    {
        int m=read();
        for(int j=1;j<=m;j++)
            b[j].x=read(),b[j].y=read();
        for(int j=1;j<=m;j++) a[++tot]=trans(b[j],b[j%m+1]);
    }
    solve();
    double res=0;
    for(int i=1;i<=tot;i++) res+=(ans[i]^ans[i%tot+1]);
    printf("%.3lf\n",res/2);
    return 0;
}

更新日志

  • 2020/04/19 一代初稿
  • 2021/01/29 二代初稿
  • 2022/08/15 几乎重构了整篇文章。
  • 2023/02/14 重构了一些数据结构板子。
  • 2023/10/19 再次重构,优化模板代码的可迁移性,删除了部分过于基础的模板。

重写了几乎所有的代码,现在应该能保证正确性,且码风差不多统一了。

缺什么东西可以评论区把 yxcat 抓回来加。

posted @ 2021-01-29 22:39  樱雪喵  阅读(2029)  评论(11编辑  收藏  举报