常用模板

快读/快写

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 @   basicecho  阅读(85)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示