模板集合

正向表

int tot=0,h[M];
struct edge{
    int nxt;
    int to,cost;
}G[3*M];
void add(int a,int b,int c){
    G[++tot]=(edge){h[a],b,c};
    h[a]=tot;
}

LCA

跳重链

void dfs(int x,int f,int d){
	dep[x]=d;
	sz[x]=1;
	fa[x]=f;son[x]=0; 
	for(int i=0;i<G[x].size();i++){
		int u=G[x][i];
		if(u==f)continue;
		dfs(u,x,d+1);
		if(sz[u]>sz[son[x]])son[x]=u;
		sz[x]+=sz[u];
	}
}
void dfs_top(int x,int tp){
	top[x]=tp;
	if(son[x])dfs_top(son[x],tp);
	for(int i=0;i<G[x].size();i++){
		int u=G[x][i];
		if(u==fa[x]||u==son[x])continue;
		dfs_top(u,u);
	}
}
int LCA(int a,int b){
	while(top[a]!=top[b]){
		if(dep[top[a]]>dep[top[b]])a=fa[top[a]];
		else b=fa[top[b]];
	}
	return dep[a]>dep[b]?b:a;
}

倍增

void dfs(int x,int f,int d){
	dep[x]=d;
	fa[x][0]=f;
	for(int i=0;i<G[x].size();i++){
		int u=G[x][i];
		if(u==f)continue;
		dfs(u,x,d+1);
	}
}
int LCA(int a,int b){
	if(dep[a]>dep[b])swap(a,b);
	int step=dep[b]-dep[a];
	for(int i=19;i>=0;i--)
		if(step&1<<i)b=fa[b][i];
	if(a==b)return a;
	for(int i=19;i>=0;i--)
		if(fa[a][i]!=fa[b][i])a=fa[a][i],b=fa[b][i];
	return fa[a][0];
} 
for(int j=1;j<=19;j++)
	for(int i=1;i<=n;i++)
		fa[i][j]=fa[fa[i][j-1]][j-1];

st表

预处理

void Init_RMQ(int n){
	for(int i=1;i<=n;i++)f[i][0]=A[i];
	lg2[1]=0;
	for(int i=2;i<=n;i++)lg2[i]=lg2[i>>1]+1;
	for(int j=1;(1<<j)<=n;j++)
		for(int i=1;i+(1<<j)-1<=n;i++)
			f[i][j]=max(f[i][j-1],f[i+(1<<(j-1))][j-1]);
} 

查询

int query(int l,int r){
	int k=lg2[r-l+1];
	return max(f[l][k],f[r-(1<<k)+1][k]);
}

数学

扩展欧几里得算法

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

逆元

int inv(int a){
    ll x,y,d;
    exgcd(a,m,d,x,y);
    return (x%MOD+MOD)%MOD;
}

线性筛逆元

void Init(){
	fac[0]=1;rev[1]=1;
	for(int i=1;i<=n;i++)
		fac[i]=(fac[i-1]*i)%MOD;
	for(int i=2;i<=n;i++)//线性筛逆元 
		rev[i]=(MOD-MOD/i)*rev[MOD%i]%MOD;
}

高斯消元

void gauss(int n){
	for(int i=1;i<=n;i++){
		int r=i;
		for(int j=i+1;j<=n;j++)//找到后面这一项最大的数 
			if(fabs(a[j][i])>fabs(a[r][i]))
				r=j;
		for(int j=1;j<=n+1;j++) 
			swap(a[i][j],a[r][j]);
		for(int j=i+1;j<=n;j++){
			double f=1.0*a[j][i]/a[i][i];
			for(int k=i;k<=n+1;k++)
				a[j][k]-=f*a[i][k];
		}
	}
	for(int i=n;i>=1;i--){
		for(int j=i+1;j<=n;j++)
			a[i][n+1]-=a[j][n+1]*a[i][j];
		a[i][n+1]/=a[i][i];
	}
}

中国剩余定理

for(int op=0;op<4;op++){//for需要合并的模数
    LL x,y,d;
    LL M=(mod-1)/md[op];//所有模数之和除以当前模数
    exgcd(M,md[op],d,x,y);//求出当前模数对于这个值的逆元
    x=(x%md[op]+md[op])%md[op];
    po=(po+tmp[op]*x%(mod-1)*M%(mod-1))%(mod-1);//合并上去
}

Lucas定理

LL lucas(LL a,LL b){
    LL res=1;
    while(a&&b){
        LL x=a%mod,y=b%mod;if(y>x)return 0;
        res=res*C(x,y)%mod;
        a/=mod;b/=mod;
    }
    return res;
}

树链剖分

寻找重儿子

void dfs(int x,int f,int d){
	dep[x]=d;fa[x]=f;sz[x]=1;son[x]=0;
	for(int i=h[x];i;i=G[i].nxt){
		int u=G[i].to;
		if(u==f)continue;
		dfs(u,x,d+1); 
		if(sz[u]>sz[son[x]])son[x]=u;
		sz[x]+=sz[u];
	}
}

处理top

void dfs_top(int x,int tp){
	top[x]=tp;ID[x]=++tt;ln[tt]=x;
	if(son[x])dfs_top(son[x],tp);
	for(int i=h[x];i;i=G[i].nxt){
		int u=G[i].to;
		if(u==son[x]||u==fa[x])continue;
		dfs_top(u,u);
	}
}

query

while(top[u]!=top[v]){
	if(dep[top[u]]>dep[top[v]]){
		query(ID[top[u]],ID[u],1);
		u=fa[top[u]];
	}
	else {
		query(ID[top[v]],ID[v],1);
		v=fa[top[v]];
	}
} 
if(dep[u]>dep[v])query(ID[v],ID[u],1);
else query(ID[u],ID[v],1);

“一起“二分

主要是利用归并的性质。

以3351为例:

#include<bits/stdc++.h>
#define M 100005
#define LL long long
#define P 131071
using namespace std;
struct erfen{
    int l,r,mid,ans,id;
    bool operator < (const erfen& res) const{
        return mid<res.mid;  
    }
}F[M];
int n,A[M],m;
int X[M],Y[M],Ans[M];
LL Val[P+5];
void Add(int k){
    Val[X[k]]+=Y[k];
}
LL calc(int k){
    LL res=0;
    for(int i=k;i<=P;i=((i+1)|k)){
        res+=Val[i];
    }
    return 1LL*A[k]-res;
}
int main(){
//  freopen("monster.in","r",stdin);
//  freopen("monster.out","w",stdout);
    cin>>n;
    for(int i=0;i<n;i++)scanf("%d",&A[i]);
    cin>>m;
    for(int i=1;i<=m;i++)scanf("%d%d",&X[i],&Y[i]),X[i]&=P;
    for(int i=0;i<n;i++)F[i].l=1,F[i].r=m,F[i].ans=-1,F[i].id=i;//二分当前怪兽是在哪个点死的,如果不是则ans=-1 
    int Time=20;
    while(Time--){
        for(int i=0;i<n;i++)F[i].mid=(F[i].l+F[i].r)>>1;
        for(int i=0;i<=P;i++)Val[i]=0;
        sort(F,F+n);
        int cur=1;
        for(int i=0;i<n;i++){
            if(F[i].l>F[i].r)continue;
            while(cur<=F[i].mid&&cur<=m){Add(cur);cur++;}
            if(calc(F[i].id)<=0){
                F[i].ans=F[i].mid;
                F[i].r=F[i].mid-1;
            }
            else F[i].l=F[i].mid+1;
        }
    }
    for(int i=0;i<n;i++){
        if(F[i].ans==-1)continue;
        Ans[F[i].ans]--;//当前时间少了一只 
    }
    Ans[0]=n;
    for(int i=1;i<=m;i++)Ans[i]+=Ans[i-1];
    for(int i=1;i<=m;i++)printf("%d\n",Ans[i]); 
    return 0;
}
posted @ 2021-10-15 19:15  zeroy0410  阅读(57)  评论(0编辑  收藏  举报