常用模板

快读/快写

inline int read(){
    int x=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    return x*f;
}
inline void print(int x) {
    if(x<0){putchar('-');x=-x;}
    if(x/10)print(x/10);
    putchar(x%10+'0');
}

st表查找max和min(可查位置)

struct ST {
    int n,mx[M][22],mn[M][22],a[M];
    void init() {//这里一定要注意变量的使用
        for(int i=1;i<=n;i++)mx[i][0]=mn[i][0]=i;
        for(int j=1;j<20;j++)
            for(int i=1;i+(1<<j)-1<=n;i++) {
                mx[i][j]=a[mx[i][j-1]] > a[mx[i+(1<<(j-1))][j-1]] ? mx[i][j-1] : mx[i+(1<<(j-1))][j-1];
                mn[i][j]=a[mn[i][j-1]] < a[mn[i+(1<<(j-1))][j-1]] ? mn[i][j-1] : mn[i+(1<<(j-1))][j-1];
            }
    }
    int get_max(int l,int r) {
        int k=log2(r-l+1);
        return a[mx[l][k]] > a[mx[r-(1<<k)+1][k]] ? a[mx[l][k]] : a[mx[r-(1<<k)+1][k]];
    }
    int get_min(int l,int r) {
        int k=log2(r-l+1);
        return a[mn[l][k]] < a[mn[r-(1<<k)+1][k]] ? a[mn[l][k]] : a[mn[r-(1<<k)+1][k]]; 
    }
    int get_max_pos(int l,int r) {
        int k=log2(r-l+1);
        return a[mx[l][k]] > a[mx[r-(1<<k)+1][k]] ? mx[l][k] : mx[r-(1<<k)+1][k];
    }
    int get_min_pos(int l,int r) {
        int k=log2(r-l+1);
        return a[mn[l][k]] < a[mn[r-(1<<k)+1][k]] ? mn[l][k] : mn[r-(1<<k)+1][k];
    }
}st;

树状数组(单点和区间)

struct BIT {
    int n,c[M],c1[M],c2[M];
    void init() {
        for(int i=0;i<=n+2;i++)c[i]=c1[i]=c2[i]=0;
    }
    int lowbit(int x) {return x&-x;}
    
    //单点修改
    void add(int x,int v) {
        for(int i=x;i<=n;i+=lowbit(i))
            c[i]+=v;
    }
    int sum(int x) {//单点查找
        int ans=0;
        for(int i=x;i>0;i-=lowbit(i))
            ans+=c[i];
        return ans;
    }
    int query(int l,int r) {//区间查找
        return sum(r)-sum(l-1);
    }
    
    //区间修改
    void ADD(int x,int v) {
        for(int i=x;i<=n;i+=lowbit(i))
            c1[i]+=v ,c2[i]+=v*x;
    }
    void range_add(int l,int r,int v) {
        ADD(l,v);ADD(r+1,-v);
    }
    int QUERY(int x) {//前缀和查找
        int ans=0;
        for(int i=x;i;i-=lowbit(i))
            ans+=(x+1)*c1[i]-c2[i];
        return ans;
    }
    int range_query(int l,int r) {
        return QUERY(r)-QUERY(l-1);
    }
}tr;

tarjan(缩点)

struct Suo_Point {
    int h1[M],h2[M],ne[M<<1],e[M<<1],tot;
    void add(int h[],int from,int to) {
        e[++tot]=to;  ne[tot]=h[from];  h[from]=tot;
    }
    
    int dfn[M],low[M],cnt;
    int id[M],num[M],scnt;
    bool vis[M];
    stack<int>st;
    void tarjan(int now) {
        dfn[now]=low[now]=++cnt;
        st.push(now);
        vis[now]=1;
        for(int i=h1[now];i;i=ne[i]) {
            int to=e[i];
            if(dfn[to]==0) {
                tarjan(to);
                low[now]=min(low[now],low[to]);
            }
            else if(vis[to])low[now]=min(low[now],dfn[to]);
        }
        if(dfn[now]==low[now]) {
            scnt++;
            while(1) {
                int k=st.top();
                st.pop();
                vis[k]=0;
                id[k]=scnt;
                num[scnt]++;
                if(k==now)break;
            }
        }
    }
    
    int n,m,in[M];
    void solve() {
        for(int i=1;i<=n;i++)
            if(dfn[i]==0)tarjan(i);
        
        for(int i=1;i<=n;i++)//重构图
            for(int j=h1[i];j;j=ne[j]) {
                int to=e[j];
                if(id[i]!=id[to]) {
                    add(h2,id[i],id[to]);
                    in[id[i]]++;
                }
            }//图建好了
    }
}graph;

割点

struct Cut_point {
    int h[M],ne[M],e[M],tot=1;
    void add(int from,int to) {
        e[++tot]=to;  ne[tot]=h[from];  h[from]=tot;
    }
    
    int n,m;
    int dfn[M],low[M],cnt;
    bool vis[M];
    void tarjan(int now,int fa) {//判断出那些是割点
        dfn[now]=low[now]=++cnt;
        int x=0;
        for(int i=h[now];i;i=ne[i]) {
            int to=e[i];
            if(dfn[to]==0) {
                tarjan(to,fa);
                low[now]=min(low[now],low[to]);
                if(now==fa)x++;
                if(now!=fa&&low[to]>=dfn[now])vis[now]=1;
            }
            low[now]=min(low[now],dfn[to]);
        }
        if(x>=2&&now==fa)vis[fa]=1;
    }
    void init() {
        for(int i=1;i<=n;i++)
            if(dfn[i]==0)tarjan(i,i);
    }
    
}graph;

树链剖分

struct ShuLian {//注释部分为进行取模
    int h[M],ne[M<<1],e[M<<1],tot;
    void add(int from,int to) {
        e[++tot]=to;  ne[tot]=h[from];  h[from]=tot;
    }
    
    int dep[M],f[M],son[M],siz[M];
    void dfs1(int now,int fa) {
        dep[now]=dep[fa]+1;
        siz[now]=1;
        f[now]=fa;
        for(int i=h[now];i;i=ne[i]) {
            int to=e[i];
            if(to==fa)continue;
            dfs1(to,now);
            siz[now]+=siz[to];
            if(siz[to]>siz[son[now]])son[now]=to;
        }
    }
    
    int dfn[M],idx[M],top[M],id;
    void dfs2(int now,int fa) {
        dfn[now]=++id;
        idx[id]=now;
        top[now]=fa;
        if(son[now]==0)return ;
        dfs2(son[now],fa);
        for(int i=h[now];i;i=ne[i]) {
            int to=e[i];
            if(dfn[to]==0)dfs2(to,to);
        }
    }
    
    #define ul (u<<1)
    #define ur (u<<1|1)
    struct Tree {
        int l,r,len;
        int sum,la;//和,懒标记
    }tr[M<<2];
    int n,a[M];
    
    void pu(int u) {
        tr[u].sum=(tr[ul].sum+tr[ur].sum);
        //tr[u].sum%=mod;
    }
    
    void pd(int u) {
        if(tr[u].la==0)return ;
        
        tr[ul].sum=(tr[ul].sum+tr[u].la*tr[ul].len);
        tr[ur].sum=(tr[ur].sum+tr[u].la*tr[ur].len);
        tr[ul].la=(tr[ul].la+tr[u].la);
        tr[ur].la=(tr[ur].la+tr[u].la);
        
        //tr[ul].sum%=mod;tr[ur].sum%=mod;tr[ul].la%=mod;tr[ur].la%=mod;
        tr[u].la=0;
    }
    
    void build(int u,int l,int r) {
        tr[u]={l,r,r-l+1,0,0};
        if(l==r) {
            tr[u].sum=a[idx[l]];
            //tr[u].sum=a[idx[l]]%mod;
            return ;
        }
        int mid=(l+r)>>1;
        build(ul,l,mid);
        build(ur,mid+1,r);
        pu(u);
    }

    void up(int u,int l,int r,int v) {
        if(tr[u].l>r||tr[u].r<l)return ;
        if(tr[u].l>=l&&tr[u].r<=r) {
            tr[u].sum=(tr[u].sum+tr[u].len*v);
            tr[u].la=(tr[u].la+v);
            //tr[u].sum%=mod;tr[u].la%=mod;
            return ;
        }
        pd(u);
        up(ul,l,r,v);
        up(ur,l,r,v);
        pu(u);
    }

    int query(int u,int l,int r) {
        if(tr[u].l>r||tr[u].r<l)return 0ll;
        if(tr[u].l>=l&&tr[u].r<=r)return tr[u].sum;
        pd(u);
        return (query(ul,l,r)+query(ur,l,r));
        //return (query(ul,l,r)+query(ur,l,r))%mod;
    }
    
    void change(int x,int y,int v) {//对两个点之间进行修改
        while(top[x]!=top[y]) {
            if(dep[top[x]]<dep[top[y]])swap(x,y);
            up(1,dfn[top[x]],dfn[x],v);
            x=f[top[x]];
        }
        if(dfn[x]>dfn[y])swap(x,y);
        up(1,dfn[x],dfn[y],v);
    }


    int ask(int x,int y) {//对两个点之间进行查询
        int res=0;
        while(top[x]!=top[y]) {
            if(dep[top[x]]<dep[top[y]])swap(x,y);
            res+=query(1,dfn[top[x]],dfn[x]);
            //res%=mod;
            x=f[top[x]];
        }
        if(dfn[x]>dfn[y])swap(x,y);
        res+=query(1,dfn[x],dfn[y]);
       // res%=mod;//不要忘记取模
        return res;
    }
    
    void UP(int x,int y) {//更新这个树及它的子树
        up(1,dfn[x],dfn[x]+siz[x]-1,y);
    }
    
    int QUERY(int x) {//查找这个树及它的子树的和
        return query(1,dfn[x],dfn[x]+siz[x]-1);
    }
    
    void init(int rot=1) {//初始化
        dfs1(rot,0);
        dfs2(rot,0);
        build(1,1,n);
    }
    
}Tr;

lCA(树剖)

struct LCA_ShuLian {
    int h[M],ne[M<<1],e[M<<1],tot;
    void add(int from,int to) {
        e[++tot]=to;  ne[tot]=h[from];  h[from]=tot;
    }
    int siz[M],f[M],son[M],dep[M];
    void dfs1(int now,int fa) {
        f[now]=fa;
        siz[now]=1;
        dep[now]=dep[fa]+1;
        for(int i=h[now];i;i=ne[i]) {
            int to=e[i];
            if(to==fa)continue;
            dfs1(to,now);
            siz[now]+=siz[to];
            if(siz[to]>siz[son[now]])son[now]=to;
        }
    }
    int top[M];
    void dfs2(int now,int rot) {
        top[now]=rot;
        if(son[now])dfs2(son[now],rot);
        for(int i=h[now];i;i=ne[i]) {
            int to=e[i];
            if(to==f[now]||to==son[now])continue;
            dfs2(to,to);
        }
    }
    int lca(int x,int y) {
        
        while(top[x]!=top[y]) {
            if(dep[top[x]]<dep[top[y]])swap(x,y);
            x=f[top[x]];
        }
        return dep[x]<dep[y]?x:y;
    }
    int dis(int x,int y) {//两点的距离
        return dep[x]+dep[y]-2*dep[lca(x,y)];
    }
}tr;

LCA(倍增)

struct LCA_st {
    int h[M],ne[M<<1],e[M<<1],tot;
    int Base=20;//超时的话,常数可以小一点
    void add(int from,int to) {
        e[++tot]=to;  ne[tot]=h[from];  h[from]=tot;
    }
    int dep[M],f[M][22];//找父亲
    void dfs(int now,int fa) {
        f[now][0]=fa;
        dep[now]=dep[fa]+1;
        for(int i=1;i<=Base;i++)
            f[now][i]=f[f[now][i-1]][i-1];
        for(int i=h[now];i;i=ne[i]) {
            int to=e[i];
            if(to==fa)continue;
            dfs(to,now);
        }
    }
    int lca(int x,int y) {
        if(dep[x]<dep[y])swap(x,y);
        for(int i=Base;i>=0;i--)
            if(dep[x]-(1<<i)>=dep[y])x=f[x][i];
        if(x==y)return x;
        for(int i=Base;i>=0;i--)
            if(f[x][i]!=f[y][i])
                x=f[x][i],y=f[y][i];
        return f[x][0];
    }
    int dis(int x,int y) {//两点的距离
        return dep[x]+dep[y]-2*dep[lca(x,y)];
    }
}tr;

二进制gcd

inline int gcd(int a, int b) {
    int az=__builtin_ctz(a),bz=__builtin_ctz(b),z=az>bz?bz:az,diff;
    b>>=bz;
    while(a) {
        a>>=az;
        diff=b-a;
        az=__builtin_ctz(diff);
        if(a<b)b=a;
        a=diff<0?-diff:diff;
    }
    return b<<z;
}

dinic

struct Max_flow {
    int h[N],ne[M<<1],e[M<<1],w[M<<1],tot=1;
    void add(int from,int to,int wi) {//建立双向边
        e[++tot]=to;  w[tot]=wi;  ne[tot]=h[from];  h[from]=tot;
        e[++tot]=from;w[tot]=0;   ne[tot]=h[to];    h[to]=tot;
    }
    int S=N-2,T=N-1;
    int cur[N],dep[N];
    bool bfs() {//深搜判断是否可以到达
        memcpy(cur,h,sizeof(h));
        memset(dep,0,sizeof(dep));
        queue<int>q;
        q.push(S);
        dep[S]=1;
        while(!q.empty()) {
            int now=q.front();
            q.pop();
            for(int i=h[now];i;i=ne[i]) {
                int to=e[i];
                if(dep[to]==0&&w[i]>0)
                    dep[to]=dep[now]+1,q.push(to);
            }
        }
        return dep[T];
    }
    int dfs(int now,int sum) {//进行匹配
        if(now==T)return sum;
        int ans=0;
        for(int i=cur[now];i&&sum;i=ne[i]) {
            cur[now]=i;
            int to=e[i];
            if(dep[to]==dep[now]+1&&w[i]>0) {
                int k=dfs(to,min(sum,w[i]));
                if(k==0)dep[to]=0;
                w[i]-=k;
                w[i^1]+=k;
                sum-=k;
                ans+=k;
            }
        }
        return ans;
    }
    int dinic() {//总流量
        int ans=0;
        while(bfs())ans+=dfs(S,inf);
        return ans;
    }
}flow;

费用流(最小费用EK)

struct Cost_flow {
    int h[N],ne[M],e[M],w[M],c[M],tot=1;
    void add(int from,int to,int wi,int ci) {
        e[++tot]=to;  w[tot]=wi;  c[tot]=ci;  ne[tot]=h[from];  h[from]=tot;
        e[++tot]=from;w[tot]=0;   c[tot]=-ci; ne[tot]=h[to];    h[to]=tot;
    }
    int S=N-2,T=N-1;
    bool st[N];
    int dis[N],flow[N],pre[N];
    bool spfa() {
        memset(dis,0x3f,sizeof(dis));
        memset(flow,0,sizeof(flow));
        queue<int>q;q.push(S);
        flow[S]=inf;dis[S]=0;st[S]=1;
        while(!q.empty()) {
            int now=q.front();
            q.pop();st[now]=0;
            for(int i=h[now];i;i=ne[i]) {
                int to=e[i];
                if(w[i]>0&&dis[to]>dis[now]+c[i]) {
                    dis[to]=dis[now]+c[i];
                    pre[to]=i;
                    flow[to]=min(flow[now],w[i]);
                    if(st[to]==0)st[to]=1,q.push(to);
                }
            }
        }
        return flow[T];
    }
    int EK() {
        int sum=0,ans=0;//流量 费用
        while(spfa()) {
            int tmp=flow[T];
            ans+=tmp*dis[T];
            sum+=tmp;
            for(int i=T;i!=S;i=e[pre[i]^1]) {
                w[pre[i]]-=tmp;
                w[pre[i]^1]+=tmp;
            }
        }
        cout<<sum<<' '<<ans<<endl;
        return ans;
    }
}flow;
//如果要跑最大费用,直接将费用取负数就可以了

KMP算法模板(可以不止字符串匹配)

struct KMP {
    char s[M];
    int ne[M],n;
    void init() {
        for(int i=2,j=0;i<=n;i++) {
            while(j&&s[i]!=s[j+1])j=ne[j];
            if(s[i]==s[j+1])j++;
            ne[i]=j;
        }
    }
    void find(char *t) {
        int m=strlen(t+1);//在t中进行查找,t的长度是m
        for(int i=1,j=0;i<=m;i++) {
            while(j&&t[i]!=s[j+1])j=ne[j];
            if(t[i]==s[j+1])j++;
            if(j==n) {//到这里就是匹配完了,就看需要怎么处理
                cout<<i-n+1<<'\n';
                j=ne[j];
            }
        }
    }
}kmp;

Manacher

struct Manacher {
    char s[M<<1],t[M];
    int p[M],n=1,m;
    void init() {
        m=strlen(t+1);
        s[0]='@';s[1]='#';
        for(int i=1;i<=m;i++)
            s[++n]=t[i],s[++n]='#';
        for(int i=1,mid=0,r=0;i<=n;i++) {//每个点的回文长度是p[i]-1
            if(i<=r)p[i]=min(p[2*mid-i],r-i+1);
            while(s[i-p[i]]==s[i+p[i]])p[i]++;
            if(p[i]+i>r)mid=i,r=i+p[i]-1;
        }
    }
}Ma;
//需要输入的是t

PAM(回文树)

struct PAM {
    char s[M];
    int len[M],fail[M],num[M],ch[M][26],tot=1,n;
    int get_fail(int x,int i) {
        while(i-len[x]-1<=0||s[i-len[x]-1]!=s[i])x=fail[x];
        return x;
    }
    void init() {
        fail[0]=1;len[1]=-1;
        n=strlen(s+1);
        int p=0;
        for(int i=1;i<=n;i++) {
            int fa=get_fail(p,i);
            if(!ch[fa][s[i]-'a']) {
                fail[++tot]=ch[get_fail(fail[fa],i)][s[i]-'a'];
                ch[fa][s[i]-'a']=tot;
                len[tot]=len[fa]+2;
            }
            p=ch[fa][s[i]-'a'];
            num[p]++;
        }//如果是要求当前这个位置有多少个回文,直接加上fail的数量就可以了
    }
    void get_num() {
        for(int i=tot;i>=2;i--)//求每一种回文串的数量
            num[fail[i]]+=num[i];
    }
}pam;

二分图匹配

struct Max_match {
    int vis[M],match[M],t[M];
    int n,m;//左边和右边
    void init(int nn,int mm) {
        n=nn,m=mm;//左边和右边
        for(int i=0;i<=max(n,m);i++)
            vis[i]=t[i]=match[i]=-1;
    }
    bool dfs(int now,int num) {
        for(int i=h[now];i;i=ne[i]) {
            int to=e[i];
            if(vis[to]==num)continue;
            vis[to]=num;
            if(match[to]==-1||dfs(match[to],num)) {
                match[to]=now;
                return 1;
            }
        }
        return 0;
    }
    int find() {
        int ans=0;
        for(int i=1;i<=n;i++)
            if(dfs(i,i))ans++;
        return ans;
    }
}Match;
//这里都是用的从1开始的数据,如果有要求,直接在find中修改,可以直接改为从0开始

后缀数组

struct Suffix_Array {
    char s[M];
    int sa[M],rk[M],height[M];//排名为i的是谁,i的排名
    int cnt[M],id[M],k1[M],pre[M<<1];
    int n,m;
    
    bool cmp(int l1,int l2,int len) {
        return pre[l1]==pre[l2]&&pre[l1+len]==pre[l2+len];
    }
    
    void init() {
        n=strlen(s+1),m=150;
        
        for(int i=1;i<=m;i++)cnt[i]=0;
        for(int i=1;i<=n;i++)cnt[rk[i]=s[i]]++;
        for(int i=1;i<=m;i++)cnt[i]+=cnt[i-1];
        for(int i=n;i>=1;i--)sa[cnt[rk[i]]--]=i;
        
        for(int len=1;;len<<=1) {
            int k=0;
            for(int i=n;i>n-len;i--)id[++k]=i;//没有第二关键词的,直接放在前面就行了,然后比较第一关键词
            //剩下的按照第二关键词的顺序,去存储第一关键词
            for(int i=1;i<=n;i++)
                if(sa[i]>len)id[++k]=sa[i]-len;
            
            for(int i=1;i<=m;i++)cnt[i]=0;
            for(int i=1;i<=n;i++)cnt[k1[i]=rk[id[i]]]++;
            for(int i=1;i<=m;i++)cnt[i]+=cnt[i-1];
            for(int i=n;i>=1;i--)sa[cnt[k1[i]]--]=id[i];//对第一关键词进行排序
            
            for(int i=0;i<=n;i++)pre[i]=rk[i];//比较只能对上一次的信息进行利用
            int p=0;
            for(int i=1;i<=n;i++)rk[sa[i]]=cmp(sa[i-1],sa[i],len)?p:++p;
            if(p==n)break;
            m=p;
        }
        //这个是有一个定理在里面的
        for(int i=1,k=0;i<=n;i++) {
            if(k)k--;
            while(s[i+k]==s[sa[rk[i]-1]+k])k++;
            height[rk[i]]=k;
        }
    }
}SA;

SAM

struct Suffix_Auto {
    char s[M];
    int np=1,tot=1,n;
    int ch[M<<1][26],fa[M<<1],len[M<<1],siz[M<<1],d[M];
    void insert(int c,int id) {
        int p=np;np=++tot;
        len[np]=len[p]+1;siz[np]=1;d[id]=tot;
        for(;p&&!ch[p][c];p=fa[p])ch[p][c]=np;
        if(!p)fa[np]=1;
        else {
            int q=ch[p][c];
            if(len[p]+1==len[q])fa[np]=q;
            else {
                int nq=++tot;len[nq]=len[p]+1;
                memcpy(ch[nq],ch[q],sizeof(ch[q]));
                fa[nq]=fa[q];fa[q]=fa[np]=nq;
                for(;p&&ch[p][c]==q;p=fa[p])ch[p][c]=nq;
            }
        }
    }
    
    int a[M<<1],b[M<<1];//b是代表排名为i的是谁
    void Sort() {//对节点进行排序处理,也就是大的满足,小的也一定满足,类似于topsort
        for(int i=1;i<=tot;i++)a[len[i]]++;
        for(int i=1;i<=n;i++)a[i]+=a[i-1];
        for(int i=1;i<=tot;i++)b[a[len[i]]--]=i;
    }
    
    int h[M<<1],e[M<<1],ne[M<<1],cnt;
    void add(int from,int to) {
        e[++cnt]=to;  ne[cnt]=h[from];  h[from]=cnt;
    }
    
    void build() {
        scanf("%s",s+1);
        n=strlen(s+1);
        for(int i=1;i<=n;i++)insert(s[i]-'a',i);
        for(int i=2;i<=tot;i++)add(fa[i],i);//建图
		Sort();
        for(int i = tot; i >= 1; i--)siz[fa[b[i]]] += siz[b[i]];
    }
}SAM;

单调栈

void Up_Stk(int n, int a[], int l[], int r[]) {
    for(int i = 1; i <= n; i++) {
        int j = i;
        while(j > 1 && a[j - 1] <= a[i])j = l[j -1];
        l[i] = j;
    }
    for(int i = n; i; i--) {
        int j = i;
        while(j < n && a[j + 1] < a[i])j = r[j + 1];
        r[i] = j;
    }
}

可持久化01tire

struct Lasting_01tire {
    const int N = 30;
    struct node {
        int ch[2], cnt;
    }tr[M * 32];
    int rot[M], tot;
    void insert(int pre, int &now, int i, int x) {
        tr[now = ++tot] = tr[pre];
        tr[now].cnt++;
        if(i < 0)return ;
        int v = x >> i & 1;
        tr[now].ch[v ^ 1] = tr[pre].ch[v ^ 1];
        insert(tr[pre].ch[v], tr[now].ch[v], i - 1, x);
    }
    int query(int l, int r, int x) {//直接传入你需要匹配的范围就可以了
        l = l > 1 ? rot[l - 2] : 0;
        r = rot[r];
        int ans = 0;
        for(int i = N; i >= 0; i--) {
            int v = x >> i & 1;
            if(tr[tr[r].ch[v ^ 1]].cnt - tr[tr[l].ch[v ^ 1]].cnt) {
                ans += 1 << i;
                l = tr[l].ch[v ^ 1];
                r = tr[r].ch[v ^ 1];
            }
            else {
                l = tr[l].ch[v];
                r = tr[r].ch[v];
            }
        }
        return ans;
    }
    void reset(int n) {
        for(int i = 0; i <= n + 1; i++)rot[i] = 0;
        for(int i = 0; i <= tot; i++)
            tr[i].ch[0] = tr[i].ch[1] = tr[i].cnt = 0;
        tot = 0;
    }
    void build(int n, int sum[]) {//这里是已经前缀和过的数组
        reset(n);
        insert(0, rot[0], N, 0);
        for(int i = 1; i <= n; i++)
            insert(rot[i - 1], rot[i], N, sum[i]);
    }
}Tr;

线段树动态开点

//可以不限制定义域,但是空间代价较大
#define ls(u) tr[u].ls
#define rs(u) tr[u].rs
#define la(u) tr[u].la
#define sum(u) tr[u].sum
 
int cnt=1;
struct node {
    int ls,rs;
    ll la,sum;
}tr[M*45];
 
void pd(int u,ll len) {//区间长度
    if(len<=1)return ;
    if(!ls(u))ls(u)=++cnt;
    if(!rs(u))rs(u)=++cnt;
    sum(ls(u))+=la(u)*(len/2);
    la(ls(u))+=la(u);
    sum(rs(u))+=la(u)*(len-len/2);
    la(rs(u))+=la(u);
    la(u)=0;
}
 
void pu(int u) {
    sum(u)=sum(ls(u))+sum(rs(u));
}
 
ll query(int l,int r,int u=1,int cl=1,int cr=1e9) {
    if(cl>=l&&cr<=r)return sum(u);
    pd(u,cr-cl+1);
    int mid=(cl+cr-1)/2;
    ll ans=0;
    if(mid>=l)ans+=query(l,r,ls(u),cl,mid);
    if(mid<r)ans+=query(l,r,rs(u),mid+1,cr);
    return ans;
}
 
void up(int l,int r,ll v,int u=1,int cl=1,int cr=1e9) {
    if(cl>=l&&cr<=r) {
        sum(u)+=v*(cr-cl+1);
        la(u)+=v;
        return ;
    }
    pd(u,cr-cl+1);
    int mid=(cl+cr-1)/2;
    if(mid>=l)up(l,r,v,ls(u),cl,mid);
    if(mid<r)up(l,r,v,rs(u),mid+1,cr);
    pu(u);
}
 
void add(int l,int r,int v) {
    up(l,r,v);
}
 
ll que(int l,int r) {
    return query(l,r);
}

线段树(正确性还有待测试)

struct Segment {
    #define ls(u) u<<1
    #define rs(u) u<<1|1
    #define mx(u) tr[u].mx
    #define mn(u) tr[u].mn
    #define la(u) tr[u].la
    #define len(u) (tr[u].r-tr[u].l+1)
    #define sum(u) tr[u].sum
    
    //树的结构体定义
    struct node {
        int l,r;
        int la;
        int mx,mn,sum;
    }tr[M<<2];
    
    //向上进行更新
    void pu(int u) {
        sum(u)=sum(ls(u))+sum(rs(u));
        mx(u) =max(mx(ls(u)),mx(rs(u)));
        mn(u) =min(mn(ls(u)),mn(rs(u)));
    }
    
    //单点进行更新
    void update(int u,int v) {
        sum(u)+=len(u)*v;
        mx(u)+=v;
        mn(u)+=v;
        la(u)+=v;
    }
    
    //向下进行更新
    void pd(int u) {
        if(la(u)) {
            update(ls(u),la(u));
            update(rs(u),la(u));
            la(u)=0;
        }
    }
    
    //建树
    void build(int u,int l,int r) {
        tr[u]={l,r};
        if(l==r) {
            return ;
        }
        int mid=(l+r)/2;
        build(ls(u),l,mid);
        build(rs(u),mid+1,r);
        pu(u);
    }
    
    //区间进行查询
    int query(int u,int l,int r) {
        if(tr[u].l>=l&&tr[u].r<=r) {//合法
            return 0;
        }
        if(tr[u].l>r||tr[u].r<l) {//不合法
            return 0;
        }
        pd(u);
        query(ls(u),l,r);
        query(rs(u),l,r);
        return 0;
    }
    
    //区间进行更新
    void up(int u,int l,int r,int v) {
        if(tr[u].l>=l&&tr[u].r<=r) {
            update(u,v);
            return ;
        }
        if(tr[u].l>r||tr[u].r<l) {
            return ;
        }
        pd(u);
        up(ls(u),l,r,v);
        up(rs(u),l,r,v);
        pu(u);
    }
    
    //单点进行更新
    void up(int u,int pos,int v) {
        if(tr[u].l==pos&&tr[u].l==tr[u].r) {
            
            return ;
        }
        if(tr[u].l>pos||tr[u].r<pos) {
            return ;
        }
        pd(u);
        up(ls(u),pos,v);
        up(rs(u),pos,v);
        pu(u);
    }
}Tr;

组合数学

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int M=1e6+5,mod=998244353;

int kpow(int a,int b) {
    int ans=1;
    while(b) {
        if(b&1)ans=ans*a%mod;
        b>>=1;
        a=a*a%mod;
    }
    return ans;
}

#define inv(x) kpow(x,mod-2)
int fact[M],infact[M];
void init(int n=3e5) {
    fact[0]=1;
    for(int i=1;i<=n;i++)fact[i]=fact[i-1]*i%mod;
    infact[n]=inv(fact[n]);
    for(int i=n-1;i>=0;i--)infact[i]=infact[i+1]*(i+1)%mod;
}

int C(int a,int b) {
    if(b<0||a<b)return 0;
    //cout<<a<<' '<<b<<endl;
    return fact[a]*infact[b]%mod*infact[a-b]%mod;
}

void add(int &x,int y) {
    x=(x%mod+y%mod)%mod;
}

树直径上的点

void dfs2(int id,int now,int fa) {
	b[id]=max(b[id],dep[now]);//找到最大的点
	if(fa!=0)v[id].push_back(now); 
	for(int i=h[now];i;i=ne[i]) {
		int to=e[i];
		if(to==fa||st[to])continue;
		dep[to]=dep[now]+1;
		dfs2(id,to,now);
	}
}

	dep[1]=1,dfs1(1,0);
	dep[root]=1,dfs1(root,0);
	while(root) {//找到直径上所有的点 
		a[++cnt]=root;
		st[root]=1;
		root=fa[root];
	}

并查集终极形态

map<int,int>fa;
int find(int x) {
    return fa[x]==0?x:fa[x]=find(fa[x]);
}

st表二分

int fun1(int x) {//查左边 
	int k=x;
	for(int i=19;i>=0;i--) {
		if(k>(1<<i)&&__gcd(a[x],f[k-(1<<i)][i])==a[x])
			k-=1<<i;
	}
	return k;
}

int fun2(int x) {//查右边 
	int k=x;
	for(int i=19;i>=0;i--) {
		if(k+(1<<i)<=n&&__gcd(a[x],f[k+1][i])==a[x])
			k+=1<<i;
	}	
	return k;
}
posted @ 2022-11-14 08:11  basicecho  阅读(101)  评论(0)    收藏  举报