线性递推求逆元
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=3e6+1;
int n;
ll p,inv[N];
int main(){
ios::sync_with_stdio(0);
cin>>n>>p;
inv[1]=1;
/*
设 t=p/i k=p%i
则 p=ti+k
下面用'='表示同余
0=ti+k (mod p)
-k=ti (mod p)
这里的除号表示乘以它的逆元
-k/ki=ti/ki(mod p)
1/i=-t/k (mod p)
即inv[i]=-(p/i)*inv[p%i] (mod p)
即inv[i]=(p-(p/i)*inv[p%i]%p)%p;
*/
for(int i=2;i<=n;i++) inv[i]=(p-(p/i)*inv[p%i]%p)%p;
for(int i=1;i<=n;i++) cout<<inv[i]<<"\n";
return 0;
}
组合数求解
const int N=1e6+1,V=1e6;
const ll R=1e8+7;
int T,n,m;
ll fac[N],inv[N];
inline ll power(ll a,ll b){
ll ans=1;
for(;b;b>>=1){
if(b&1) (ans*=a)%=R;
(a*=a)%=R;
}
return ans;
}
void init(){
fac[0]=inv[0]=1;
for(int i=1;i<=V;i++) fac[i]=(fac[i-1]*i)%R;
inv[V]=power(fac[V],R-2);
for(int i=V-1;i>=1;i--) inv[i]=(inv[i+1]*(i+1))%R;
}
inline ll C(int x,int y){
if(x<y) return 0;
return (1ll*fac[x]*inv[y]%R*inv[x-y]+R)%R;
}
字典树
int t[N][27],len,n,m,tot[N],cnt;
char s[N];
inline void insrt(){
int p=0;
len=strlen(s+1);
for(int i=1;i<=len;i++){
int c=s[i]-'a'+1;
if(!t[p][c]) t[p][c]=++cnt;
p=t[p][c];
}
tot[p]++;
}
inline int check(){
int p=0,ans=0;
len=strlen(s+1);
for(int i=1;i<=len;i++){
int c=s[i]-'a'+1;
p=t[p][c];
if(!p) break;
ans+=tot[p];
}
return ans;
}
可持久化线段树
int build(int l,int r){
int p=++tot;
if(l==r) return p;
int mid=(l+r)/2;
tree[p].l=build(l,mid);
tree[p].r=build(mid+1,r);
}
int insert(int p,int l,int r,int x){
int q=++tot;
tree[q]=tree[p];
if(l==r){
tree[q].data++;
return q;
}
int mid=(l+r)/2;
if(x<=mid) tree[q].l=insert(tree[p].l,l,mid,x);
else if(x>mid) tree[q].r=insert(tree[p].r,mid+1,r,x);
tree[q].data=tree[tree[q].l].data+tree[tree[q].r].data;
return q;
}
单调队列
#include<bits/stdc++.h>
#define size (r-l+1)
#define dpos (q[r].pos-q[l].pos+1)
using namespace std;
const int N=1e6+1;
int n,k,a[N],l,r;
struct Node{
int val,pos;
}q[N];
int main(){
ios::sync_with_stdio(0);
cin>>n>>k;
for(int i=1;i<=n;i++) cin>>a[i];
l=1,r=0;
for(int i=1;i<=n;i++){
while(size&&q[r].val>=a[i]) r--;
r++;
q[r].val=a[i],q[r].pos=i;
while(dpos>k) l++;
if(i>=k) cout<<q[l].val<<" ";
}
cout<<"\n";
l=1,r=0;
for(int i=1;i<=n;i++){
while(size&&q[r].val<=a[i]) r--;
r++;
q[r].val=a[i],q[r].pos=i;
while(dpos>k) l++;
if(i>=k) cout<<q[l].val<<" ";
}
return 0;
}
长链剖分lca
void dfs1(int cur,int last){
fa[cur]=last;
depthmax[cur]=depth[cur]=depth[last]+1;
for(int i=head[cur];i;i=edge[i].nxt){
int ver=edge[i].to;
if(ver==last) continue;
dfs1(ver,cur);
if(depthmax[ver]>depthmax[cur]) son[cur]=ver,depthmax[cur]=depthmax[ver];
}
}
void dfs2(int cur,int topf){
top[cur]=topf;
if(!son[cur]) return;
dfs2(son[cur],topf);
for(int i=head[cur];i;i=edge[i].nxt){
int ver=edge[i].to;
if(ver==fa[cur]||ver==son[cur]) continue;
dfs2(ver,ver);
}
}
int query(int x,int y){
while(top[x]!=top[y]){
if(depth[top[x]]<depth[top[y]]) swap(x,y);
x=fa[top[x]];
}
if(depth[x]<depth[y]) return x;
else return y;
}
splay
#include<bits/stdc++.h>
using namespace std;
const int N=1e7+5;
int sz[N],cnt[N],fa[N],son[N][2],val[N],rt=0,tot=0;
void geng(int x){sz[x]=sz[son[x][0]]+sz[son[x][1]]+cnt[x];}
void lian(int x,int f,int u){fa[x]=f,son[f][u]=x;}
bool getson(int x){return son[fa[x]][1]==x;}
void zhuan(int x){
int y=fa[x],z=fa[y],u=getson(x),v=getson(y);
lian(x,z,v),lian(son[x][u^1],y,u),lian(y,x,u^1);
geng(y),geng(x);
}
void splay(int x){
for(int f=fa[x];f;zhuan(x),f=fa[x])
if(fa[f])zhuan(getson(x)==getson(f)?f:x);
rt=x;
}
void jia(int &x,int k,int f){
if(!x){
x=++tot,sz[tot]=cnt[tot]=1,val[tot]=k,fa[tot]=f,son[tot][0]=son[tot][1]=0;
return splay(x);
}
sz[x]++;
if(k==val[x])cnt[x]++;
else if(k>val[x])jia(son[x][1],k,x);
else jia(son[x][0],k,x);
}
int pai1(int x,int k){
if(k==val[x]){splay(x);return sz[son[x][0]]+1;}
if(k>val[x])return pai1(son[x][1],k);
return pai1(son[x][0],k);
}
int pai2(int x,int k){
if(sz[son[x][0]]>=k)return pai2(son[x][0],k);
k-=(sz[son[x][0]]+cnt[x]);
if(k<=0){splay(x);return val[x];}
else return pai2(son[x][1],k);
}
int qian(int k){
int x=rt,ans;
while(x){
if(k>val[x])ans=x,x=son[x][1];
else x=son[x][0];
}
return val[ans];
}
int hou(int k){
int x=rt,ans;
while(x){
if(k<val[x])ans=x,x=son[x][0];
else x=son[x][1];
}
return val[ans];
}
void shan(int k){
pai1(rt,k);
if(--cnt[rt])return;
if(!son[rt][0]&&!son[rt][1])rt=0;
else if(!son[rt][0])rt=son[rt][1],fa[rt]=0,geng(rt);
else if(!son[rt][1])rt=son[rt][0],fa[rt]=0,geng(rt);
else{
int k=rt,tmp=son[rt][0];
while(son[tmp][1])tmp=son[tmp][1];
splay(tmp),fa[son[k][1]]=rt,son[rt][1]=son[k][1],geng(rt);
}
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
int n,op,x;
cin>>n;
while(n--){
cin>>op>>x;
switch(op){
case 1:jia(rt,x,0);break;//插入x数;
case 2:shan(x);break;//删除x数;
case 3:cout<<pai1(rt,x)<<'\n';break;//查询x数的排名(若有多个相同的数,因输出最小的排名);
case 4:cout<<pai2(rt,x)<<'\n';break;//查询排名为x的数;
case 5:cout<<qian(x)<<'\n';break;//求x的前趋(前趋定义为小于x,且最大的数);
case 6:cout<<hou(x)<<'\n';break;//求x的后继(后继定义为大于x,且最小的数)。
}
}
return 0;
}
三分模板
while(l+eps<r){
lmid=l+(r-l)/3;
rmid=r-(r-l)/3;
if(calc(lmid)<calc(rmid)) r=rmid;
else l=lmid;
}
树上启发式合并 dsu on tree
#include<bits/stdc++.h>
#define lowbit(x) ((x)&(-(x)))
using namespace std;
const int N=1e5+1,M=2e5+1;
int n,m,f[N],sz[N],son[N];
int tot,head[N],ver[M],nxt[M];
int c[N],ans[N];
struct Node{//离散化数组
int val,pos;
}a[N];
inline bool cmpval(Node A,Node B){
return A.val<B.val;
}
inline bool cmppos(Node A,Node B){
return A.pos<B.pos;
}
inline void addedge(int x,int y){//加边
tot++;
ver[tot]=y;
nxt[tot]=head[x];
head[x]=tot;
}
void compress(){//离散化
sort(a+1,a+n+1,cmpval);
for(int i=1;i<=n;i++){
if(a[i+1].val!=a[i].val) m++;
a[i].val=m;
}
sort(a+1,a+n+1,cmppos);
}
inline void dfs(int x){//找到重儿子
sz[x]=1;
for(int i=head[x];i;i=nxt[i]){
int y=ver[i];
dfs(y);
sz[x]+=sz[y];
if(sz[y]>sz[son[x]]) son[x]=y;
}
}
inline void add(int x,int y){//树状数组...这道题需要使用,普通的dsu维护桶
for(;x<=m;x+=lowbit(x)) c[x]+=y;
}
inline int ask(int x){
int sum=0;
for(;x;x-=lowbit(x)) sum+=c[x];
return sum;
}
inline void add(int x){
add(a[x].val,1);
for(int i=head[x];i;i=nxt[i]){
int y=ver[i];
add(y);
}
}
inline void del(int x){
add(a[x].val,-1);
for(int i=head[x];i;i=nxt[i]){
int y=ver[i];
del(y);
}
}
inline void solve(int x){
for(int i=head[x];i;i=nxt[i]){
int y=ver[i];
if(y==son[x]) continue;
solve(y);//走轻儿子
del(y);//删轻儿子
}
if(son[x]) solve(son[x]);//走重儿子
for(int i=head[x];i;i=nxt[i]){
int y=ver[i];
if(y==son[x]) continue;
add(y);//加轻儿子
}
add(a[x].val,1);//加自己
ans[x]=sz[x]-ask(a[x].val);//统计答案
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i].val;
a[i].pos=i;
}
for(int i=2;i<=n;i++){
cin>>f[i];
addedge(f[i],i);
}
compress();
dfs(1);
solve(1);
for(int i=1;i<=n;i++) cout<<ans[i]<<"\n";
return 0;
}
快速乘
inline int(int a,int b,int p)
{
int s=0;
while(b)
{
if(b&1)s=s+a%p;
a=a+a%p;
b>>=1;
}
return s;
}