蒟蒻的模板
快要爆零了敲些模板复习复习,随缘更新
P3379 【模板】最近公共祖先(LCA)注意t的取值
#include<bits/stdc++.h>
using namespace std;
const int size=500010;
int n,m,t,f[size][25],root;
int head[size],ver[2*size],Next[2*size],d[size],tot;
queue<int>q;
void add(int x,int y){
ver[++tot]=y;Next[tot]=head[x];head[x]=tot;
}
void bfs(){
q.push(root);d[root]=1;
while(q.size()){
int x=q.front();q.pop();
for(int i=head[x];i;i=Next[i]){
int y=ver[i];
if(d[y]) continue;
d[y]=d[x]+1;
f[y][0]=x;
for(int j=1;j<=t;++j){
f[y][j]=f[f[y][j-1]][j-1];
}
q.push(y);
}
}
}
int lca(int x,int y){
if(d[x]>d[y]) swap(x,y);
for(int i=t;i>=0;i--){
if(d[f[y][i]]>=d[x]){
y=f[y][i];
}
}
if(x==y) return x;
for(int i=t;i>=0;i--){
if(f[y][i]!=f[x][i]){
y=f[y][i];
x=f[x][i];
}
}
return f[x][0];
}
int main(){
scanf("%d %d %d",&n,&m,&root);
t=((int)(log(n)/(log(2))))+1;
for(int i=1;i<n;++i){
int x,y;
scanf("%d %d",&x,&y);
add(x,y);add(y,x);
}
bfs();
for(int i=1;i<=m;++i){
int x,y;
scanf("%d %d",&x,&y);
printf("%d\n",lca(x,y));
}
return 0;
}
P3378 【模板】堆(注意更新当前坐标
#include<bits/stdc++.h>
using namespace std;
const int size=1000010;
int a[size],n,k,x,add;
void shiftdown(int x){
int t;bool flag=1;
while(2*x<=add&&flag){
if(a[x*2]<a[x]) t=x*2;
else t=x;
if(2*x+1<=add&&a[x*2+1]<a[t]) t=2*x+1;
if(t!=x){
swap(a[t],a[x]);
x=t;
} else flag=0;
}
}
void updown(int x){
bool flag=1;
if(x==1) return;
while(x!=1&&flag){
if(a[x/2]>a[x]) swap(a[x/2],a[x]);
else flag=0;
x/=2;
}
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;++i){
scanf("%d",&k);
if(k==1){
scanf("%d",&x);
a[++add]=x;
updown(add);
}
else if(k==2) printf("%d\n",a[1]);
else{
a[1]=a[add--];
shiftdown(1);
}
}
return 0;
}
P4549 【模板】裴蜀定理( $ gcd $ 很重要
#include<bits/stdc++.h>
using namespace std;
int n,x,ans;
int gcd(int a,int b){
return b?gcd(b,a%b):a;
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;++i){
scanf("%d",&x);
x=x<0?-x:x;
ans=gcd(x,ans);
}printf("%d",ans);
return 0;
}
P3390 【模板】矩阵快速幂(不开 $ longlong $ 见祖宗 $ n,k $ 都要开。
#include<bits/stdc++.h>
using namespace std;
const int mod=1e9+7;
long long n,k;
struct node{
long long s[110][110];
}a,ans;
node mul(node a,node b){
node c;
for(int i=1;i<=n;++i){
for(int j=1;j<=n;++j){
c.s[i][j]=0;
}
}
for(int i=1;i<=n;++i){
for(int j=1;j<=n;++j){
for(int k=1;k<=n;++k){
c.s[i][j]=(c.s[i][j]+(a.s[i][k]*b.s[k][j])%mod)%mod;
}
}
}
return c;
}
int main(){
scanf("%lld %lld",&n,&k);
for(int i=1;i<=n;++i){
for(int j=1;j<=n;++j){
scanf("%lld",&a.s[i][j]);
ans.s[i][i]=1;
}
}
while(k){
if(k&1) ans=mul(ans,a);
a=mul(a,a);
k>>=1;
}
for(int i=1;i<=n;++i){
for(int j=1;j<=n;++j){
printf("%lld ",ans.s[i][j]%mod);
}printf("\n");
}
return 0;
}
P3385 【模板】负环
注意初始化,输出,还有spfa出了队列标记要变
#include<bits/stdc++.h>
using namespace std;
const int N=2010;
const int M=6010;
int tot,deg[N],head[N],ver[M],edge[M],Next[M];
int v[N],dis[N];
queue<int>q;
int T,n,m;
void add(int x,int y,int z){
ver[++tot]=y;edge[tot]=z;Next[tot]=head[x];head[x]=tot;
}
bool spfa(){
memset(v,0,sizeof(v));
memset(deg,0,sizeof(deg));
memset(dis,0x3f,sizeof(dis));
dis[1]=0;v[1]=1;q.push(1);
while(q.size()){
int x=q.front();q.pop();v[x]=0;
if(deg[x]==n-1) return false;deg[x]++;
for(int i=head[x];i;i=Next[i]){
int y=ver[i];
if(dis[y]>dis[x]+edge[i]){
dis[y]=dis[x]+edge[i];
if(!v[y]){v[y]=1,q.push(y);}
}
}
}return true;
}
int main(){
scanf("%d",&T);
while(T--){
scanf("%d %d",&n,&m);
memset(head,0,sizeof(head));tot=0;
for(int i=1;i<=m;++i){
int x,y,z;
scanf("%d %d %d",&x,&y,&z);
z>=0?add(x,y,z),add(y,x,z):add(x,y,z);
}
spfa()?printf("N0\n"):printf("YE5\n");
}
return 0;
}
P3372 【模板】线段树 1
蒟蒻线段树区间修改区间查询还敲不出,我太菜了,考前在敲一遍
#include<bits/stdc++.h>
using namespace std;
const int size=100010;
struct node{
long long l,r,data,add;
}t[4*size];
long long a[size];
int n,m,num,x,y;
long long k;
void build(long long p,long long l,long long r){
t[p].l=l,t[p].r=r;
if(l==r){t[p].data=a[l];return;}
long long mid=(l+r)>>1;
build(p*2,l,mid);
build(p*2+1,mid+1,r);
t[p].data=t[p*2].data+t[p*2+1].data;
}
void lazy(long long p){
if(t[p].add){
t[p*2].data+=t[p].add*(t[p*2].r-t[p*2].l+1);
t[p*2+1].data+=t[p].add*(t[p*2+1].r-t[p*2+1].l+1);
t[p*2].add+=t[p].add;
t[p*2+1].add+=t[p].add;
t[p].add=0;
}
}
void change(long long p,long long l,long long r,long long v){
if(l<=t[p].l&&r>=t[p].r){t[p].data+=v*(t[p].r-t[p].l+1);t[p].add+=v;return;}
lazy(p);
int mid=(t[p].l+t[p].r)>>1;
if(l<=mid) change(p*2,l,r,v);
if(r>mid) change(p*2+1,l,r,v);
t[p].data=t[p*2].data+t[p*2+1].data;
}
long long ask(long long p,long long l,long long r){
if(l<=t[p].l&&r>=t[p].r) return t[p].data;
lazy(p);
long long mid=(t[p].l+t[p].r)>>1;
long long val=0;
if(l<=mid) val+=ask(p*2,l,r);
if(r>mid) val+=ask(p*2+1,l,r);
return val;
}
int main(){
scanf("%d %d",&n,&m);
for(int i=1;i<=n;++i) scanf("%lld",&a[i]);
build(1,1,n);
for(int i=1;i<=m;++i){
scanf("%d",&num);
if(num==1){
scanf("%d %d %lld",&x,&y,&k);
change(1,x,y,k);
}else{
scanf("%d %d",&x,&y);
printf("%lld\n",ask(1,x,y));
}
}
return 0;
}
P4777 【模板】扩展中国剩余定理(EXCRT)
这个以前敲的,先挂着,有时间来敲
#include<bits/stdc++.h>
using namespace std;
const int maxn=300010;
long long a[maxn],b[maxn],ans;
int n;
long long clu(long long a,long long b,long long p){
long long tmp=0;
while(b>0){
if(b&1) tmp=(tmp+a)%p;
a=(a+a)%p;
b>>=1;
}
return tmp;
}
long long exgcd(long long a,long long b,long long &x,long long &y){
if(b==0){
x=1,y=0;
return a;
}
long long gcd=exgcd(b,a%b,x,y);
long long tmp=x;
x=y,y=tmp-a/b*y;
return gcd;
}
long long solve(){
long long x,y,k;
long long M=a[1];
ans=b[1];
for(int i=2;i<=n;++i){
long long ai=M,bi=a[i],c=(b[i]-ans%bi+bi)%bi;
long long gcd=exgcd(ai,bi,x,y),tmp=bi/gcd;
if(c%gcd!=0) return -1;
x=clu(x,c/gcd,tmp);
ans+=x*M;
M*=tmp;
ans=(ans%M+M)%M;
}
return (ans%M+M)%M;
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;++i){
scanf("%lld %lld",&a[i],&b[i]);
}
printf("%lld",solve());
return 0;
}
P3382 【模板】三分法
秦九昭公式求多项式一开始打反了。。。什么 $ lj $ 样例,次数大的先扫,注意从0开始,其余三分模板
#include<bits/stdc++.h>
using namespace std;
const double esp=1e-9;
int n;
double l,r,ans,xi[20];
double clu(double x){
double ans=0;
for(int i=0;i<=n;++i){
ans=ans*x+xi[i];
}
return ans;
}
int main(){
scanf("%d %lf %lf",&n,&l,&r);
for(int i=0;i<=n;++i){
scanf("%lf",&xi[i]);
}
while(l+esp<=r){
double lm=l+(r-l)/3.0;
double rm=r-(r-l)/3.0;
if(clu(lm)<clu(rm)) l=lm;
else r=rm;
}printf("%.5lf",l);
return 0;
}
P2197 【模板】nim游戏
水题不多说,可以参照hdu 1850
#include<bits/stdc++.h>
using namespace std;
int T,n;
int main(){
scanf("%d",&T);
while(T--){
scanf("%d",&n);
int ans=0,k;
for(int i=1;i<=n;++i) scanf("%d",&k),ans^=k;
ans?printf("Yes\n"):printf("No\n");
}
return 0;
}
P4779 【模板】单源最短路径(标准版)
$ dijkstra $ 无法处理负环,并且写法上同spfa有差异。
注意stl
priority_queue< node> q
bool poerator <(const node &x)const{return x.dis<dis;}
注意注意!!$ spfa $ 中 $ v $ 表示是否在队列里,而 $ dijkstra $表示是否拓展
#include<bits/stdc++.h>
using namespace std;
const int size=100010;
int n,m,s;
int head[size],ver[2*size],Next[2*size],edge[2*size],tot;
int dis[size],v[size];
struct node{
int dis;
int num;
bool operator <(const node &x) const{
return x.dis<dis;
}
};
priority_queue<node>q;
void add(int x,int y,int z){
ver[++tot]=y;edge[tot]=z;Next[tot]=head[x];head[x]=tot;
}
void dija(){
memset(dis,0x3f,sizeof(dis));
memset(v,0,sizeof(v));
dis[s]=0;q.push((node){0,s});
while(q.size()){
int x=q.top().num;q.pop();
if(v[x]) continue;v[x]=1;//只能扩展一次
for(int i=head[x];i;i=Next[i]){
int y=ver[i];
if(dis[y]>dis[x]+edge[i]){
dis[y]=dis[x]+edge[i];
if(!v[y]){q.push((node){dis[y],y});}//这里不需要标记
}
}
}
}
int main(){
scanf("%d %d %d",&n,&m,&s);
for(int i=1;i<=m;++i){
int x,y,z;
scanf("%d %d %d",&x,&y,&z);
add(x,y,z);
}
dija();
for(int i=1;i<=n;++i){
printf("%d ",dis[i]);
}
return 0;
}
P3386 【模板】二分图匹配(匈牙利算法
连单向边,并且判断边的存在才能去匹配
#include<bits/stdc++.h>
using namespace std;
const int size=1010;
int n,m,e;
int a[size][size],v[size],match[size];
bool dfs(int x){
for(int i=1;i<=m;++i){
if(a[x][i]){
if(v[i]) continue;
v[i]=1;
if(match[i]==-1||dfs(match[i])){
match[i]=x;
return 1;
}
}
}return 0;
}
int solve(){
int ans=0;
memset(match,-1,sizeof(match));
for(int i=1;i<=n;++i){
memset(v,0,sizeof(v));
if(dfs(i)) ans++;
}
return ans;
}
int main(){
scanf("%d %d %d",&n,&m,&e);
for(int i=1;i<=e;++i){
int x,y;
scanf("%d %d",&x,&y);
if(x>=1&&x<=n&&y>=1&&y<=m) a[x][y]=1;
}
printf("%d",solve());
return 0;
}
P3366 【模板】最小生成树 $ Kruskal $
#include<bits/stdc++.h>
using namespace std;
const int N=5010;
const int M=400010;
struct node{
int u,v,dis;
}edge[M];
int n,m,tot=1;
int fa[N];
long long ans;
bool cmp(node a,node b){
return a.dis<b.dis;
}
int find(int x){
return x==fa[x]?x:fa[x]=find(fa[x]);
}
int main(){
scanf("%d %d",&n,&m);
for(int i=1;i<=m;++i){
int x,y,z;
scanf("%d %d %d",&edge[i].u,&edge[i].v,&edge[i].dis);
}
for(int i=1;i<=n;++i) fa[i]=i;
sort(edge+1,edge+1+m,cmp);
for(int i=1;i<n;++i){
while(find(edge[tot].u)==find(edge[tot].v)) tot++;
fa[find(edge[tot].u)]=find(edge[tot].v);ans+=edge[tot].dis;
}printf("%lld",ans);
return 0;
}
P3366 【模板】最小生成树 $ Prim $
#include<bits/stdc++.h>
using namespace std;
const int N=5010;
const int M=400010;
int n,m;
long long ans;
int tot,head[N],ver[M],Next[M],edge[M];
int v[N],dis[N];
void add(int x,int y,int z){
ver[++tot]=y;edge[tot]=z;Next[tot]=head[x];head[x]=tot;
}
int main(){
scanf("%d %d",&n,&m);
for(int i=1;i<=m;++i){
int x,y,z;
scanf("%d %d %d",&x,&y,&z);
add(x,y,z);add(y,x,z);
}
memset(dis,0x3f,sizeof(dis));
memset(v,0,sizeof(v));
v[1]=1;dis[1]=0;
for(int i=head[1];i;i=Next[i]){
int y=ver[i],z=edge[i];
dis[y]=min(dis[y],z);
}
for(int t=1;t<n;++t){
int minn=1<<30;
int op=1;
for(int i=1;i<=n;++i){
if(!v[i]&&dis[i]<minn){
minn=dis[i];
op=i;
}
}
if(v[op]) continue;
v[op]=1;ans+=minn;
for(int i=head[op];i;i=Next[i]){
int y=ver[i];
if(!v[y]&&dis[y]>edge[i]){
dis[y]=edge[i];
}
}
}
ans>1<<30?printf("orz"):printf("%lld",ans);
return 0;
}