常用baozi
快读,不解释(也有一种(x<<3)+(x<<1)的写法,一样的)
int read() { int x=0,b=1;char c=getchar(); while(!isdigit(c)) b=c=='-'?-1:1,c=getchar(); while(isdigit(c)) x=x*10+c-'0',c=getchar(); return x*b; }
数组实现线段树(不解释,注意细节不要写错就可)
#include <stdio.h> #include <algorithm> #include <cstring> using namespace std; const int maxn=200000; int sum[maxn],a[maxn],add[maxn]; int n; void build(int k,int l,int r) { if(l==r) { sum[k]=a[l]; return; } int mid=l+r>>1; build(k<<1,l,mid); build(k<<1|1,mid+1,r); sum[k]=sum[k<<1]+sum[k<<1|1]; } void ADD(int k,int l,int r,int v) { add[k]+=v; sum[k]+=(r-l+1)*v; } void pushdown(int k,int l,int r,int mid) { if(add[k]==0) return; ADD(k<<1,l,mid,add[k]); ADD(k<<1|1,mid+1,r,add[k]); add[k]=0; } void change(int k,int l,int r,int x,int y,int v) { if(l>=x&&r<=y) { ADD(k,l,r,v); return; } int mid=l+r>>1; pushdown(k,l,r,mid); if(mid>=x) change(k<<1,l,mid,x,y,v); if(mid<y) change(k<<1|1,mid+1,r,x,y,v); sum[k]=sum[k<<1]+sum[k<<1|1]; } int query(int k,int l,int r,int x,int y) { if(l>=x&&r<=y) return sum[k]; int mid=l+r>>1; pushdown(k,l,r,mid); int res=0; if(mid>=x)res+=query(k<<1,l,mid,x,y); if(mid<y) res+=query(k<<1|1,mid+1,r,x,y); return res; } int main() { scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]); build(1,1,n); while(1) { int k;scanf("%d",&k); if(k==1) { int a,b; scanf("%d%d",&a,&b); printf("%d",query(1,1,n,a,b)); } else { int a,b,c; scanf("%d%d%d",&a,&b,&c); change(1,1,n,a,b,c); } } return 0; }
扩展GCD
int ecgcd(int a,int b,int &x,int &y) { if(b==0) { x=1,y=0; } else exgcd(b,a%b,y,x) y-=a/b*x; } x=(x+p)%p
堆优化的prime算法
#include <stdio.h> #include <algorithm> #include <cstring> #include <queue> using namespace std; const int maxn=400020;//注意无向图要开两倍的大小 int head[maxn],nex[maxn],ver[maxn],wei[maxn],tot; bool vis[maxn]; int dis[maxn],cnt; int n,m,sum; typedef pair<int,int> pii; priority_queue<pii,vector<pii>,greater<pii> > q; void add(int x,int y,int w) { ver[++tot]=y; wei[tot]=w; nex[tot]=head[x]; head[x]=tot; } void prime() { memset(dis,0x3f,sizeof(dis)); dis[1]=0; q.push(make_pair(0,1));//注意这里插入的时候是make_pair(0,1) while(q.size()&&cnt<n) { pii t=q.top();q.pop(); int x=t.second,d=t.first; if(vis[x]) continue; cnt++; sum+=d;//这里d数组存储的就仅仅只是每一个点到外面的最短边的距离了 vis[x]=1; for(int i=head[x];i;i=nex[i]) { int y=ver[i]; if(dis[y]>wei[i]) { dis[y]=wei[i]; q.push(make_pair(dis[y],y)); } } } } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=m;i++) { int a,b,c; scanf("%d%d%d",&a,&b,&c); add(a,b,c); add(b,a,c); } prime(); if(cnt==n) printf("%d",sum); else printf("orz"); return 0; }
树链剖分+区间修改线段树
#include <stdio.h> #include <algorithm> #include <cstring> #define lson (k<<1) #define rson (k<<1|1) #define mid ((l+r)>>1) using namespace std; const int maxn=100020; int s[maxn<<1],tag[maxn<<1]; int n,m,rt,p; int dep[maxn],sz[maxn],fa[maxn],son[maxn]; int rev[maxn],id[maxn],idx,top[maxn]; int a[maxn]; int head[maxn<<1],nex[maxn<<1],ver[maxn<<!1],tot; void add(int x,int y) { ver[++tot]=y; nex[tot]=head[x]; head[x]=tot; } void dfs(int x,int f) { dep[x]=dep[f]+1;fa[x]=f;sz[x]=1; for(int i=head[x];i;i=nex[i]) { int y=ver[i]; if(y==f) continue; dfs(y,x); sz[x]+=sz[y]; if(sz[y]>sz[son[x]])son[x]=y; } } void dfs2(int x,int t) { id[x]=++idx;rev[id[x]]=x;top[x]=t; if(!son[x]) return; dfs2(son[x],t); for(int i=head[x];i;i=nex[i]) { int y=ver[i]; if(y!=fa[x]&&y!=son[x]) dfs2(y,y); } } void build(int k,int l,int r) { if(l==r) { s[k]=a[rev[l]]; return ; } build(lson,l,mid); build(rson,mid+1,r); s[k]=(s[lson]+s[rson])%p; } void pushdown(int k,int l,int r)//1?¡Á¡é?¨¤¨¤? { if(!tag[k]) return ; tag[lson]=(tag[lson]+tag[k])%p; tag[rson]=(tag[rson]+tag[k])%p; s[lson]=(s[lson]+(mid-l+1)*tag[k])%p; s[rson]=(s[rson]+(r-mid)*tag[k])%p;//tag标记的下传要理解,整体区间就不需要下传,否则就更新左右两端点并且下传 tag[k]=0; return ; } void change(int k,int l,int r,int x,int y,int v) { if(l>y||r<x||l>r) return ; if(l>=x&&r<=y) { tag[k]=(tag[k]+v)%p; s[k]=(s[k]+(r-l+1)*v)%p;//注意这里要return 并且长度是(r-l+1)所以一定要注意 return; } pushdown(k,l,r); if(mid>=x) change(lson,l,mid,x,y,v); if(mid<y) change(rson,mid+1,r,x,y,v); s[k]=(s[lson]+s[rson])%p; return; } void update(int x,int y,int z) { while(top[x]!=top[y]) { if(dep[top[x]]<dep[top[y]]) swap(x,y); change(1,1,n,id[top[x]],id[x],z); x=fa[top[x]]; } if(id[x]>id[y]) swap(x,y); change(1,1,n,id[x],id[y],z); return ; } int query(int k,int l,int r,int x,int y) { if(l>y||r<x||l>r) return 0 ; if(l>=x&&r<=y) return s[k]; pushdown(k,l,r); int res=0; if(mid>=x) res+=query(lson,l,mid,x,y); if(mid<y) res+=query(rson,mid+1,r,x,y); res%=p; return res; } 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,1,n,id[top[x]],id[x]); res%=p; x=fa[top[x]]; } if(id[x]>id[y]) swap(x,y); res+=query(1,1,n,id[x],id[y]); res%=p; return res; } int main() { scanf("%d%d%d%d",&n,&m,&rt,&p); for(int i=1;i<=n;i++) scanf("%d",&a[i]); for(int i=1;i<n;i++) { int x,y; scanf("%d%d",&x,&y); add(x,y); add(y,x); } dfs(rt,0);dfs2(rt,rt); build(1,1,n); for(int i=1;i<=m;i++) { int mod;scanf("%d",&mod); int x,y,z; if(mod==1) scanf("%d%d%d",&x,&y,&z),update(x,y,z); if(mod==2) scanf("%d%d",&x,&y),printf("%d\n",ask(x,y)); if(mod==3) scanf("%d%d",&x,&y),change(1,1,n,id[x],id[x]+sz[x]-1,y); if(mod==4) scanf("%d",&x),printf("%d\n",query(1,1,n,id[x],id[x]+sz[x]-1)); } return 0; }
kruskal算法:
#include <stdio.h> #include <algorithm> #include <cstring> using namespace std; const int maxn=200020; struct node { int x,y,wei; }s[maxn]; int n,m,sum,cnt=0; int fa[maxn]; int find(int x) { while(x!=fa[x]) x=fa[x]=fa[fa[x]]; return x; } void he(int x,int y) { int t1=find(x),t2=find(y); fa[t1]=t2;//注意合并是f[t1]=t2 } bool bmp(node a,node b) { return a.wei<b.wei; } void kru() { for(int i=0;i<m;i++) { int t1=find(s[i].x),t2=find(s[i].y); if(t1==t2) continue; else { he(s[i].x,s[i].y); sum+=s[i].wei; cnt++; if(cnt==n-1) break; } } } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) fa[i]=i; for(int i=0;i<m;i++) { scanf("%d%d%d",&s[i].x,&s[i].y,&s[i].wei); } sort(s,s+m,bmp); kru(); printf("%d",sum); return 0; }
桥的求法:
#include <stdio.h> #include <algorithm> #include <cstring> using namespace std; const int maxn=5020,maxm=20020; int head[maxn],nex[maxm],ver[maxm],tot; int dcnt,id[maxn]; int du[maxn]; int low[maxn],dfn[maxn],idx,sta[maxn],top; bool bri[maxm]; int n,m; void trajan(int x,int from)//from存储的是从哪一条边过来的 { // printf("%d %d \n",x,from); low[x]=dfn[x]=++idx; sta[++top]=x; for(int i=head[x];~i;i=nex[i])//如果要使用从0开始的tot的话 那么就要用~i防止爆炸,并且之前额head需要重置成-1 { // printf("%d %d\n",x,ver[i]); int y=ver[i]; if(!dfn[y]) { trajan(y,i); low[x]=min(low[x],low[y]); if(dfn[x]<low[y])//判断条件,y永远到达不了x,那么x->y和反向边就是了 bri[i]=bri[i^1]=true; } else if(i!=(from^1)) { low[x]=min(low[x],dfn[y]);//如果不是反向边,那么就是后箱边,所以就可以直接更新(环就出现了) } } if(dfn[x]==low[x]) { dcnt++;id[x]=dcnt;//这种写法要先把x加入,但是do while就不需要了 while(sta[top]!=x) { id[sta[top]]=dcnt; top--; } top--; } } void add(int x,int y) { ver[tot]=y; nex[tot]=head[x]; head[x]=tot++; } int main() { memset(head,-1,sizeof head); scanf("%d%d",&n,&m); for(int i=1;i<=m;i++) { int a,b; scanf("%d%d",&a,&b); add(a,b),add(b,a); } //for(int i=head[1];~i;i=nex[i]) printf("%d ",ver[i]); trajan(1,-1); for(int i=0;i<tot;i++) { if(bri[i]) du[id[ver[i]]]++; } //for(int i=1;i<=n;i++) printf("%d ",id[i]); int ans=0; for(int i=1;i<=dcnt;i++) { if(du[i]==1) ans++; } //printf("%d \n",ans); printf("%d",(ans+1)/2); return 0; }
组合数的相关求法:
1.a,b较小,并且询问较多时
void init() { for(int i=0;i<maxn;i++) for(int j=0;j<=i;j++) if(!j) c[i][j]=1; else c[i][j]=(c[i-1][j]+c[i-1][j-1])%mod; }
字符串算法:kmp
#include<stdio.h> #include<algorithm> #include<cstring> using namespace std; const int maxn=20000; int p[maxn],k,n,m,ans; char a[1000],b[1000]; void pre() { int i,j; p[1]=0; j=0;// for(i=1;i<m;i++)//ÕâÀïµÄÑ»·´Ó1¿ªÊ¼£¬ÒòΪp[1]=0 { while (j>0&&b[i+1]!=b[j+1]) j=p[j]; if(b[i+1]==b[j+1]) j++; p[i+1]=j; } } int main() { int i,j; scanf("%d",&k); while(k--) { scanf("%s",a+1); scanf("%s",b+1); n=strlen(a+1);m=strlen(b+1); pre(); j=0;ans=0;//ÿ´Î´¦Àí¶¼ÐèÒªÏë×ųõʼ»¯£¨»òÕßÖØÉ裩 for(i=0;i<n;i++) { while (j>0&&a[i+1]!=b[j+1]) j=p[j]; if(a[i+1]==b[j+1]) j++; if(j==m)//ÕâÀïÊÇѰÕÒÖØ¸´ÏҪ²»È»¾ÍÐèÒªÈÃj=P[J] { ans++; j=0; } } printf("%d",ans); } return 0; }
浙公网安备 33010602011771号