Kruskal 最小生成树
重要程度:★★★★☆
熟练程度:★★★★☆
代码比较短,还是好理解,就是打的少了点
#include<iostream> #include<cstdio> #include<algorithm> using namespace std; int n,m; struct save { int from;int to;int quan; }cun[10000]; bool aaa(const save &s,const save &b) { return s.quan<b.quan; } int fa[10000]; int find(int x) { if(fa[x]!=x) fa[x]=find(fa[x]); return fa[x]; } int ans=0; int main() { cin>>n>>m;//m条路径 for(int i=1;i<=m;i++) { int x,y,z; cin>>x>>y>>z; cun[i].from=x;cun[i].to=y;cun[i].quan=z; } for(int i=1;i<=10000;i++) fa[i]=i; sort(cun+1,cun+m+1,aaa); int sum=0; for(int i=1;i<=m;i++) { int x=cun[i].from;int y=cun[i].to; if(find(x)!=find(y)) { fa[find(y)]=find(x); ans+=cun[i].quan;//cout<<ans<<" "<<i<<endl; sum++; } if(sum==n-1) break; } cout<<ans; while(1); return 0; }
Kruskal
Prim 最小生成树
重要程度:★★★☆☆
熟练程度:☆☆☆☆☆
好像只是听说过一样。几乎没怎么用过,但是有的题卡Kruskal
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> using namespace std; int n,m,sum; int a[2000][2000]; int dis[2000]; int pre[2000]; void prim(int x) { sum=0; for(int i=1;i<=n;i++) { dis[i]=a[x][i]; pre[i]=x; } dis[x]=0; for(int i=2;i<=n;i++) { int min=10000000; int k; for(int j=1;j<=n;j++) { if(dis[j]<min&&dis[j]!=0) { min=dis[j]; k=j; } } sum+=dis[k]; dis[k]=0; for(int j=1;j<=n;j++) { if(dis[j]>a[k][j]) { dis[j]=a[k][j]; pre[j]=k; } } } } int main() { cin>>n>>m; memset(a,0x3f,sizeof(a)); for(int i=1;i<=m;i++) { int x,y,z; cin>>x>>y>>z; a[x][y]=z; a[y][x]=z; } prim(1);int tot=0; cout<<sum; while(1); return 0; }
Prim
线段树
重要程度:★★★★★
熟练程度:★★★★☆
很常用也很重要的数据结构,但是自己打一些灵活的线段树有一丝丝虚
#include<iostream> #include<cstdio> #include<cstring> using namespace std; const int N=100010; int a[N]; int t; struct haha { int left,right,sum; }tree[N*4]; void buildtree(int left,int right,int i) { int mid; tree[i].left=left; tree[i].right=right; if(left==right) { tree[i].sum=a[left]; return; } mid=(left+right)>>1; buildtree(left,mid,i*2); buildtree(mid+1,right,i*2+1); tree[i].sum=tree[i*2].sum+tree[i*2+1].sum; } void add(int haha,int num,int i) { if(tree[i].left==tree[i].right) { tree[i].sum+=num; return; } else { tree[i].sum+=num; if(haha<=tree[i*2].right) add(haha,num,2*i); else add(haha,num,2*i+1); } } int query(int left,int right,int i) { int mid; if(tree[i].left==left&&tree[i].right==right) return tree[i].sum; mid=(tree[i].left+tree[i].right)>>1; if(right<=mid) return query(left,right,2*i); else if(left>mid) return query(left,right,2*i+1); else return query(left,mid,2*i)+query(mid+1,right,2*i+1); } int n; int k; int main() { //freopen("shulie.in","r",stdin); //freopen("shulie.out","w",stdout); char s[10]; scanf("%d",&n); if(n==0) return 0; for(int i=1;i<=n;i++) scanf("%d",&a[i]); buildtree(1,n,1); int qq; scanf("%d",&qq); for(int i=1;i<=qq;i++) { scanf("%s",s); int haha,num; scanf("%d%d",&haha,&num); if(s[0]==‘S‘) printf("%d\n",query(haha,num,1)); if(s[0]==‘A‘) add(haha,num,1); } //while(1); return 0; }
普通线段树
#include<iostream> #include<cstring> #include<cstdio> using namespace std; #define LL long long using namespace std; int n; const int N=101000; LL sum[N*4]; LL add[N*4]; void buildtree(int l,int r,int rt) { add[rt]=0; if(l==r) { scanf("%lld",&sum[rt]); return; } int mid=(l+r)>>1; buildtree(l,mid,rt*2); buildtree(mid+1,r,rt*2+1); sum[rt]=sum[rt<<1]+sum[rt<<1|1]; } void pushdown(int rt,int len) { if(add[rt]) { add[rt<<1]+=add[rt]; add[rt<<1|1]+=add[rt]; sum[rt<<1]+=add[rt]*(len-(len>>1)); sum[rt<<1|1]+=add[rt]*(len>>1); add[rt]=0; } } void update(int xunl,int xunr,int c,int l,int r,int rt) { if(xunl<=l&&r<=xunr) { add[rt]+=c; sum[rt]+=(LL)c*(r-l+1); return; } pushdown(rt,r-l+1); int mid=(l+r)>>1; if(xunl<=mid) update(xunl,xunr,c,l,mid,rt*2); if(mid<xunr) update(xunl,xunr,c,mid+1,r,rt*2+1); sum[rt]=sum[rt<<1]+sum[rt<<1|1]; } LL ques(int xunl,int xunr,int l,int r,int rt) { if(xunl<=l&&r<=xunr) return sum[rt]; pushdown(rt,r-l+1); int mid=(l+r)>>1; LL ans=0; if(xunl<=mid) ans+=ques(xunl,xunr,l,mid,rt*2); if(mid<xunr) ans+=ques(xunl,xunr,mid+1,r,rt*2+1); return ans; } int main() { scanf("%d",&n); buildtree(1,n,1); int m; cin>>m; char s[20]; for(int i=1;i<=m;i++) { scanf("%s",&s); int x,y,z; scanf("%d%d",&x,&y); if(s[0]==‘S‘) { printf("%lld\n",ques(x,y,1,n,1)); } if(s[0]==‘A‘) { scanf("%d",&z); update(x,y,z,1,n,1); } } //while(1); return 0; }
延迟标记线段树
扩展GCD
重要程度:★★★★★
熟练程度:★★★★☆
非常常用的数学知识,但是也有一些虚
#include<iostream> #include<cstring> #include<cstdio> using namespace std; #define LL long long LL x,y; LL kuogcd(LL a,LL b,LL &x,LL &y) { LL ret,tmp; if(b==0) { x=1; y=0; return a; } ret=kuogcd(b,a%b,x,y); tmp=x; x=y; y=tmp-a/b*y; return ret; } int main() { LL m,n; cin>>m>>n; LL z; z=kuogcd(m,n,x,y); LL t=0; while(x<0) { x+=n*t; t++; } cout<<x; //while(1); return 0; }
扩展GCD
匈牙利算法
重要程度:★★★☆☆
熟练程度:☆☆☆☆☆
最近做题很少有出现过,模板也几乎记住不了
#include <iostream> #include <string.h> #include <stdio.h> using namespace std; const int N = 2005; bool vis[N]; int link[N],head[N]; int cnt,n; struct Edge { int to; int next; }; Edge edge[N*N]; void Init() { cnt = 0; memset(head,-1,sizeof(head)); } void add(int u,int v) { edge[cnt].to = v; edge[cnt].next = head[u]; head[u] = cnt++; } bool dfs(int u) { for(int i=head[u];~i;i=edge[i].next) { int v = edge[i].to; if(!vis[v]) { vis[v] = 1; if(link[v] == -1 || dfs(link[v])) { link[v] = u; return true; } } } return false; } int match() { int ans = 0; memset(link,-1,sizeof(link)); for(int i=0;i<n;i++) { memset(vis,0,sizeof(vis)); if(dfs(i)) ans++; } return ans; } int main() { while(~scanf("%d",&n)) { Init(); for(int i=0;i<n;i++) { int u,v,k; scanf("%d:(%d)",&u,&k); while(k--) { scanf("%d",&v); add(u,v); add(v,u); } } printf("%d\n",match()>>1); } return 0; }
匈牙利算法
Tarjan缩点
重要程度:★★★★★
熟练程度:★☆☆☆☆
这么重要的知识我竟然脑子里留下的不多。看来得再多打两道题了
#include<iostream> #include<cstring> #include<cstdio> using namespace std; #define pos(i,a,b) for(int i=(a);i<=(b);i++) #define N 2000 int n,m; int in[N]; struct haha { int to,next,w; }; haha edgechu[N],edge[N]; int headchu[N],cntchu=1,head[N],cnt=1,cntt; int low[N],dfn[N],stack[N],hea,instack[N],belong[N],ji=1; void addchu(int u,int v) { edgechu[cntchu].to=v; edgechu[cntchu].next=headchu[u]; headchu[u]=cntchu++; } void add(int u,int v) { edge[cnt].to=v; edge[cnt].next=head[u]; head[u]=cnt++; } void tarjan(int now) { low[now]=dfn[now]=ji; ji++; stack[++hea]=now; instack[now]=1; for(int r=headchu[now];r;r=edgechu[r].next) { int i=edgechu[r].to; if(dfn[i]==-1) { tarjan(i); low[now]=min(low[now],low[i]); } else if(instack[i]) low[now]=min(low[now],dfn[i]); } if(low[now]==dfn[now]) { int temp; while(1) { temp=stack[hea--]; belong[temp]=cntt; instack[temp]=0; if(temp==now) break; } cntt++; } } int main() { memset(dfn,-1,sizeof(dfn)); scanf("%d%d",&n,&m); pos(i,1,m) { int x,y; scanf("%d%d",&x,&y); addchu(x,y); } pos(i,1,n) if(dfn[i]==-1) tarjan(i); pos(i,1,n) { for(int v=headchu[i];v;v=edgechu[v].next) { int j=edgechu[v].to; if(belong[i]!=belong[j]) { add(belong[i],belong[j]); in[belong[j]]++; } } } //while(1); return 0; }
Tarjan缩点
Tarjan割点割边
重要程度:★★★★☆
熟练程度:★☆☆☆☆
这个也很重要了,最近做题做过一道,却发现自己还得再照着模板打
#include<iostream> #include<cstdio> #include<cstring> #define pos(i,a,b) for(int i=(a);i<=(b);i++) #define pos2(i,a,b) for(int i=(a);i>=(b);i--) #define N 1000 using namespace std; int a[N][N]; int n; int gen,ji; int dfn[N],low[N]; bool flag[N]; int gpoint[N]; void tarjan(int now) { dfn[now]=low[now]=++ji; flag[now]=1; pos(i,1,n) { if(a[now][i]==1) { if(flag[i]==0) { tarjan(i); low[now]=min(low[now],low[i]); if(low[i]>=dfn[now]&&now!=1) gpoint[now]++; else if(now==1) gen++; } else low[now]=min(low[now],dfn[i]); } } } int ans=0; int main() { cin>>n;int x,y; while(cin>>x) { cin>>y; a[x][y]=a[y][x]=1; } tarjan(1); if(gen>=2) { ans++; gpoint[1]=1; } pos(i,2,n) if(gpoint[i]!=0) ans++; if(ans!=0) { cout<<ans<<endl; pos(i,1,n) if(gpoint[i]!=0) cout<<i<<endl; } else cout<<0; //while(1); return 0; }
Tarjan割点
/*tarjan算法--求无向图的割点和桥 一.基本概念 1.桥:是存在于无向图中的这样的一条边,如果去掉这一条边,那么整张无向图会分为两部分,这样的一条边称为桥无向连通图中,如果删除某边后,图变成不连通,则称该边为桥。 2.割点:无向连通图中,如果删除某点后,图变成不连通,则称该点为割点。 二:tarjan算法在求桥和割点中的应用 1.割点:1)当前节点为树根的时候,条件是“要有多余一棵子树”(如果这有一颗子树,去掉这个点也没有影响,如果有两颗子树,去掉这点,两颗子树就不连通了。) 2)当前节点U不是树根的时候,条件是“low[v]>=dfn[u]”,也就是在u之后遍历的点,能够向上翻,最多到u,如果能翻到u的上方,那就有环了,去掉u之后,图仍然连通。 保证v向上最多翻到u才可以 2.桥:若是一条无向边(u,v)是桥, 1)当且仅当无向边(u,v)是树枝边的时候,需要满足dfn(u)<low(v),也就是v向上翻不到u及其以上的点,那么u--v之间一定能够有1条或者多条边不能删去,因为他们之间有一部分无环,是桥。 如果v能上翻到u那么u--v就是一个环,删除其中一条路径后,能然是连通的。 3.注意点: 1)求桥的时候:因为边是无方向的,所以父亲孩子节点的关系需要自己规定一下, tarjan的过程中if(v不是u的父节点) low[u]=min(low[u],dfn[v]); 因为如果v是u的父亲,那么这条无向边就被误认为是环了。 2)找桥的时候:注意看看有没有重边,有重边的边一定不是桥,也要避免误判。 4.也可以先进行tarjan(),求出每一个点的dfn和low,并记录dfs过程中的每个点的父节点,遍历所有点的low,dfn来寻找桥和割点 三:求桥和割点的模板: */ #include<iostream> using namespace std; #include<cstdio> #include<cstring> #include<vector> #define N 201 vector<int>G[N]; int n,m,low[N],dfn[N]; bool is_cut[N]; int father[N]; int tim=0; void input() { scanf("%d%d",&n,&m); int a,b; for(int i=1;i<=m;++i) { scanf("%d%d",&a,&b); G[a].push_back(b);/*邻接表储存无向边*/ G[b].push_back(a); } } void Tarjan(int i,int Father) { father[i]=Father;/*记录每一个点的父亲*/ dfn[i]=low[i]=tim++; for(int j=0;j<G[i].size();++j) { int k=G[i][j]; if(dfn[k]==-1) { Tarjan(k,i); low[i]=min(low[i],low[k]); } else if(Father!=k)/*假如k是i的父亲的话,那么这就是无向边中的重边,有重边那么一定不是桥*/ low[i]=min(low[i],dfn[k]); //dfn[k]可能!=low[k](搜索树中的树枝边,不是搜索树的根,因为i的儿子节点k有可能通过自己的一个反向边把自己的low更新了), //所以不能用low[k]代替dfn[k],否则会上翻过头了。 } } void count() { int rootson=0; Tarjan(1,0); for(int i=2;i<=n;++i) { int v=father[i]; if(v==1) rootson++;/*统计根节点子树的个数,根节点的子树个数>=2,就是割点*/ else{ if(low[i]>=dfn[v])/*割点的条件*/ is_cut[v]=true; } } if(rootson>1) is_cut[1]=true; for(int i=1;i<=n;++i) if(is_cut[i]) printf("%d\n",i); for(int i=1;i<=n;++i) { int v=father[i]; if(v>0&&low[i]>dfn[v])/*桥的条件*/ printf("%d,%d\n",v,i); } } int main() { input(); memset(dfn,-1,sizeof(dfn)); memset(father,0,sizeof(father)); memset(low,-1,sizeof(low)); memset(is_cut,false,sizeof(is_cut)); count(); return 0; }
割点割边模板
A*
重要程度:★★★☆☆
熟练程度:★☆☆☆☆
很久没出过A*的题了,都忘了。。
#include<iostream> #include<cstdio> #include<cstring> #include<queue> using namespace std; int n,m; #define pos(i,a,b) for(int i=(a);i<=(b);i++) #define N 200000 #define INF 0x7fffffff struct haha { int to,w,next; }; haha edge1[N],edge2[N]; int head1[N],head2[N]; int cnt1=1,cnt2=1; int dis[N]; void add2(int u,int v,int w) { edge2[cnt2].w=w; edge2[cnt2].to=v; edge2[cnt2].next=head2[u]; head2[u]=cnt2++; } void add1(int u,int v,int w) { edge1[cnt1].w=w; edge1[cnt1].to=v; edge1[cnt1].next=head1[u]; head1[u]=cnt1++; } int flag[N]; void spfa(int x) { memset(dis,0x3f,sizeof(dis)); queue<int> q; flag[x]=1; dis[x]=0; q.push(x); while(!q.empty()) { int i=q.front(); for(int v=head2[i];v;v=edge2[v].next) { int j=edge2[v].to; if(dis[j]>dis[i]+edge2[v].w) { dis[j]=dis[i]+edge2[v].w; if(!flag[j]) { flag[j]=1; q.push(j); } } } flag[q.front()]=0; q.pop(); } } struct node2 { int g,f,to; bool operator<(const node2 &r )const { if(r.f==f) return r.g<g; return r.f<f; } }; int astar(int s,int t,int k) { node2 e,ne; int cnt=0; priority_queue<node2> Q; if(s==t) k++; if(dis[s]>1000000) return -1; e.to=s;e.g=0;e.f=e.g+dis[e.to]; Q.push(e); while(!Q.empty()) { e=Q.top(); Q.pop(); if(e.to==t) cnt++; if(cnt==k) return e.g; for(int i=head1[e.to];i;i=edge1[i].next) { ne.to=edge1[i].to; ne.g=e.g+edge1[i].w; ne.f=ne.g+dis[ne.to]; Q.push(ne); } } return -1; } int main() { //freopen("dota.in","r",stdin); //freopen("dota.out","w",stdout); cin>>n>>m; pos(i,1,m) { int x,y,z; scanf("%d%d%d",&x,&y,&z); add2(x,y,z); add2(y,x,z); add1(x,y,z); add1(y,x,z); } spfa(n); int p; cin>>p; if(p==0) printf("%d",dis[1]); else printf("%d",astar(1,n,2)); //while(1); return 0; }
A*
倍增LCA
重要程度:★★★★★
熟练程度:★★★☆☆
非常非常重要的,一定要记得熟熟的!其他LCA打法就先放一边吧
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> using namespace std; #define N 100000 #define pos(i,a,b) for(int i=(a);i<=(b);i++) int n,m; struct haha { int to,next,w; }edge[N]; int head[N],cnt=1; int f[N],p[N][20],deep[N],dis[N]; void add(int u,int v,int w) { edge[cnt].w=w; //cout<<"w="<<w<<endl; edge[cnt].to=v; edge[cnt].next=head[u]; head[u]=cnt++; } void dfs(int now,int fa,int de) { f[now]=fa; deep[now]=de; for(int i=head[now];i;i=edge[i].next) { int v=edge[i].to; if(v!=fa) { dis[v]=dis[now]+edge[i].w; //cout<<dis[now]<<endl; dfs(v,now,de+1); } } } void init() { int j; for(j=0;(1<<j)<=n;j++) pos(i,1,n) p[i][j]=-1; pos(i,1,n) p[i][0]=f[i]; for(j=1;(1<<j)<=n;j++) pos(i,1,n) if(p[i][j-1]!=-1) p[i][j]=p[p[i][j-1]][j-1]; } int lca(int a,int b) { int i; if(deep[a]<deep[b]) swap(a,b); for(i=0;(1<<i)<=deep[a];i++); i--; for(int j=i;j>=0;j--) if(deep[a]-(1<<j)>=deep[b]) a=p[a][j]; if(a==b) return a; for(int j=i;j>=0;j--) if(p[a][j]!=-1&&p[a][j]!=p[b][j]) { a=p[a][j]; b=p[b][j]; } return f[a]; } int main() { scanf("%d%d",&n,&m); pos(i,1,m) { int x,y,w; char r; //scanf("%d%d%d",&x,&y,&w); scanf("%d%d%d",&x,&y,&w); cin>>r; //cout<<"wwww="<<w<<endl; add(x,y,w); add(y,x,w); } //dis[1]=0; dfs(1,-1,0); init(); int k; scanf("%d",&k); while(k--) { int x,y; scanf("%d%d",&x,&y); //cout<<dis[y]<<endl; printf("%d\n",dis[x]+dis[y]-2*dis[lca(x,y)]); } //while(1); return 0; }
倍增LCA
树链剖分
重要程度:★★★★★
熟练程度:★☆☆☆☆
想当初至少打了10遍的,无奈太长还是记不太清
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> using namespace std; #define pos(i,a,b) for(int i=(a);i<=(b);i++) #define N 50000 int n; int read() { int su=0; char ch=getchar(); while(ch<‘0‘||ch>‘9‘) ch=getchar(); while(ch<=‘9‘&&ch>=‘0‘) { su=su*10+ch-‘0‘; ch=getchar(); } return su; } struct haha { int to,next,w,from; }edge[N]; struct xixi { int left,right,da; }tree[N]; int head[N],cnt=1; int size[N],son[N],dep[N],fa[N],v[N]; void add(int u,int v,int w) { edge[cnt].w=w; edge[cnt].to=v; edge[cnt].from=u; edge[cnt].next=head[u]; head[u]=cnt++; } void dfs(int x) { size[x]=1;son[x]=0; for(int i=head[x];i;i=edge[i].next) { int to=edge[i].to; if(to!=fa[x]) { fa[to]=x; v[to]=edge[i].w; dep[to]=dep[x]+1; dfs(to); size[x]+=size[to]; if(size[to]>size[son[x]]) son[x]=to; } } } int ji,pos[N],id[N],top[N]; void dfs2(int x,int tp) { top[x]=tp; id[x]=++ji; pos[ji]=x; if(son[x]) dfs2(son[x],tp); for(int i=head[x];i;i=edge[i].next) { int to=edge[i].to; if(to!=fa[x]&&to!=son[x]) dfs2(to,to); } } void build(int left,int right,int root) { tree[root].left=left; tree[root].right=right; if(left==right) { tree[root].da=v[pos[left]]; return; } int mid=(right+left)>>1; build(left,mid,root*2); build(mid+1,right,root*2+1); tree[root].da=max(tree[root<<1].da,tree[root<<1|1].da); } int query(int left,int right,int root) { int mid=(tree[root].right+tree[root].left)>>1; if(tree[root].left==left&&tree[root].right==right) return tree[root].da; if(right<=mid) return query(left,right,root*2); else if(left>mid) return query(left,right,root*2+1); else return max(query(left,mid,root*2),query(mid+1,right,root*2+1)); } int Query(int x,int y) { int fx=top[x],fy=top[y]; int ans=1<<31; while(fx^fy) { if(dep[fx]<dep[fy]) { swap(x,y); swap(fx,fy); } ans=max(ans,query(id[fx],id[x],1)); x=fa[fx];fx=top[x]; } if(dep[x]>dep[y]) swap(x,y); if(id[x]<id[y]) ans=max(ans,query(id[x]+1,id[y],1)); return ans; } void change(int pos,int val,int root,int left,int right) { if(left==right) { tree[root].da=val; return; } int mid=(left+right)>>1; if(pos<=mid) change(pos,val,root*2,left,mid); else change(pos,val,root*2+1,mid+1,right); tree[root].da=max(tree[root*2].da,tree[root*2+1].da); } char a[20]; int main() { //freopen("qtree.in","r",stdin); //freopen("qtree.out","w",stdout); n=read(); pos(i,1,n-1) { int x,y,z; x=read();y=read();z=read(); add(x,y,z);add(y,x,z); } dfs(1); dfs2(1,1); build(1,n,1); while(1) { scanf("%s",&a); if(a[0]==‘D‘) break; int x,y; x=read();y=read(); if(a[0]==‘Q‘) printf("%d\n",Query(x,y)); else { int now=x*2-1; int fr=edge[now].from; int to=edge[now].to; if(fa[fr]==to) change(id[fr],y,1,1,n); else change(id[to],y,1,1,n); } } //while(1); return 0; }
树链剖分
分块
重要程度:★★★★★
熟练程度:★★★★☆
关键时刻的救命暴力,一遍100%对还是有点虚
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> using namespace std; #define pos(i,a,b) for(int i=(a);i<=(b);i++) #define pos2(i,a,b) for(int i=(a);i>=(b);i--) #define N 50100 int t; int len,cun[N],match[N],a[N]; int n; void del() { memset(cun,0,sizeof(cun)); memset(match,0,sizeof(match)); memset(a,0,sizeof(a)); } void pre(int x) { pos(i,1,n) if(match[i]==x) cun[x]+=a[i]; } void add(int x,int y) { cun[match[x]]+=y; a[x]+=y; } int query(int x,int y) { int ans=0; if(match[x]+1>=match[y]) pos(i,x,y) ans+=a[i]; else { for(int i=x;i;i++) { if(match[i]!=match[x]) break; ans+=a[i]; } for(int i=y;i;i--) { if(match[i]!=match[y]) break; ans+=a[i]; } pos(i,match[x]+1,match[y]-1) ans+=cun[i]; } return ans; } int main() { scanf("%d",&t); pos(u,1,t) { del(); scanf("%d",&n); len=(int)sqrt(n+0.5); //while(1); pos(i,1,n) scanf("%d",&a[i]); pos(i,1,n) match[i]=(i-1)/len+1; pos(i,1,match[n]) pre(i); printf("Case %d:\n",u); char s[20]; while(1) { scanf("%s",&s); int x,y; if(s[0]==‘E‘) break; scanf("%d%d",&x,&y); if(s[0]==‘A‘) add(x,y); if(s[0]==‘S‘) add(x,-y); if(s[0]==‘Q‘) printf("%d\n",query(x,y)); } } // while(1); return 0; }
分块
字符串KMP
重要程度:★★★★★
熟练程度:★★★☆☆
字符串必备基础,但是变形还是虚
KMP
字符串Hash
重要程度:★★★★★
熟练程度:★★★☆☆
也是保命之作
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> using namespace std; #define N 1010000 #define pos(i,a,b) for(int i=(a);i<=(b);i++) #define pos2(i,a,b) for(int i=(a);i>=(b);i--) unsigned long long haxi[N],haxi2[N]; int len2,len; const int p=123; char Q[N],P[N]; int t; int aa; unsigned long long xp[N]; void Hash(int n) { memset(haxi,0,sizeof(haxi)); pos2(i,n-1,0) haxi[i]=haxi[i+1]*p+P[i]-‘A‘; } void Hash2(int n) { memset(haxi2,0,sizeof(haxi2)); pos2(i,n-1,0) haxi2[i]=haxi2[i+1]*p+Q[i]-‘A‘; xp[0]=1; pos(i,1,n) xp[i]=xp[i-1]*p; } unsigned long long gethash(int i,int j) { return haxi2[i]-haxi2[j]*xp[j-i]; } void work() { unsigned long long temp=haxi[0]; pos(i,0,len2-len) { if(temp==gethash(i,i+len)) aa++; } } int main() { scanf("%d",&t); while(t--) { aa=0; scanf("%s%s",P,Q); len=strlen(P); len2=strlen(Q); Hash(len); Hash2(len2); work(); cout<<aa<<endl; } //while(1); return 0; }
字符串Hash
Trie树
重要程度:★★★★☆
熟练程度:★☆☆☆☆
当初就打了两道题,印象很模糊了
#include<iostream> #include<cmath> #include<cstring> #include<cstdio> #define pos(i,a,b) for(int i=(a);i<=(b);i++) #define pos2(i,a,b) for(int i=(a);i>=(b);i--) #define N 500001 using namespace std; struct Trie { int dfn; Trie *ch[30]; }; Trie node[N],*root; int f[N],n,t,sz; Trie* newnode() { sz++; return &node[sz]; } void insert(char *s) { int len=strlen(s); Trie *now=root; ++t; pos(i,0,len-1) { if(now->ch[s[i]-‘a‘]==NULL) now->ch[s[i]-‘a‘]=newnode(); if(now->dfn) f[t]=max(f[now->dfn],f[t]); now=now->ch[s[i]-‘a‘]; } now->dfn=t; f[t]++; } int main() { scanf("%d",&n); root=newnode(); pos(i,1,n) { char s[60]; scanf("%s",s); insert(s); } int ans=0; pos(i,1,t) ans=max(ans,f[i]); printf("%d",ans); //while(1); return 0; }
Trie
高斯消元
重要程度:★★★★☆
熟练程度:★☆☆☆☆
概率&期望必备!但是也是记忆不清楚了
#include<iostream> #include<cmath> #include<cstring> #include<cstdio> #define pos(i,a,b) for(int i=(a);i<=(b);i++) #define pos2(i,a,b) for(int i=(a);i>=(b);i--) #define N 600 using namespace std; int n; double a[N][N],b[N],x[N]; int flag; void swap(double &xx,double &yy) { double temp; temp=xx; xx=yy; yy=temp; } int gauss() { double t; int im,num=1; for(int k=1;k<n;k++,num++) { im=k; pos(i,k+1,n) if(fabs(a[i][k])>fabs(a[im][k])) im=i; if(im!=k) { pos(i,k,n) swap(a[num][i],a[im][i]); swap(b[num],b[im]); } if(!a[num][k]) { num--; continue; } pos(i,num+1,n) { if(!a[num][k]) continue; t=a[i][k]/a[num][k]; pos(j,k,n+1) a[i][j]-=t*a[k][j]; b[i]-=t*b[k]; } } pos(i,num,n) if(!a[i][n]&&b[i]) return -1; pos2(i,n,1) { pos2(j,n,i+1) b[i]-=a[i][j]*x[j]; if(!a[i][i]&&b[i]!=0) return -1; if(!a[i][i]&&!b[i]) return 0; x[i]=b[i]/a[i][i]; } return 1; } int haha() { //freopen(".in","r",stdin); //freopen(".out","w",stdout); scanf("%d",&n); pos(i,1,n) { pos(j,1,n) scanf("%lf",&a[i][j]); scanf("%lf",&b[i]); } flag=gauss(); if(flag!=1) printf("%d",flag); else pos(i,1,n) { if(!x[i]) printf("x%d=0\n",i); else printf("x%d=%0.2lf\n",i,x[i]); } //while(1); return 0; } int sb=haha(); int main() {;}
高斯消元
网络流
重要程度:★★★☆☆
熟练程度:★☆☆☆☆
对我来说就是一个大黑箱。
#include<cstdio> #include<algorithm> #include<queue> #include<iostream> #include<cstring> using namespace std; #define LL long long #define pos(i,a,b) for(int i=(a);i<=(b);i++) #define N 40000 const int inf=0x7fffffff; struct haha{ int next,to,w; }edge[N]; int head[N],cnt; int n; void add(int u,int v,int w){ edge[cnt].w=w; edge[cnt].to=v; edge[cnt].next=head[u]; head[u]=cnt++; } int dep[N],ans; bool bfs(){ memset(dep,0,sizeof(dep)); queue<int> q; q.push(1); dep[1]=1; while(!q.empty()){ int now=q.front();q.pop(); for(int i=head[now];i!=-1;i=edge[i].next){ int to=edge[i].to,w=edge[i].w; if(w&&(!dep[to])){ dep[to]=dep[now]+1; q.push(to); if(to==n){ return 1; } } } } return 0; } int dfs(int now,int f){ if(now==n){ return f; } int tmp=f; for(int i=head[now];i!=-1;i=edge[i].next){ int to=edge[i].to,w=edge[i].w; if(w&&tmp&&dep[to]==dep[now]+1){ int k=dfs(to,min(w,tmp)); if(!k){ dep[to]=0; continue; } edge[i].w-=k; edge[i^1].w+=k; tmp-=k; } } return f-tmp; } int main(){ scanf("%d",&n); memset(head,-1,sizeof(head)); pos(i,1,n){ pos(j,1,n){ int x; scanf("%d",&x); if(x){ add(i,j,x); add(j,i,0); } } } while(bfs()){ ans+=dfs(1,inf); } cout<<ans; return 0; }
网络流最大流
#include<cstdio> #include<algorithm> #include<queue> #include<iostream> #include<cstring> using namespace std; #define LL long long #define pos(i,a,b) for(int i=(a);i<=(b);i++) #define N 10000 #define inf 0x7fffffff struct haha{ int next,to,w,cost,from; }edge[N]; int cnt=2,head[N]; int t,g,p,m,f,n,s; void add(int u,int v,int w,int c){ edge[cnt].w=w; edge[cnt].to=v; edge[cnt].cost=c; edge[cnt].from=u; edge[cnt].next=head[u]; head[u]=cnt++; } int S,T; queue<int> q; int dis[N],cun[N],flag[N],from[N],ans; int spfa(int st,int ed) { pos(i,st+1,ed){ dis[i]=inf; } flag[st]=1; q.push(st); while(!q.empty()) { int k=q.front(); q.pop(); flag[k]=0; for(int i=head[k];i;i=edge[i].next) { if(edge[i].w&&dis[edge[i].to]>dis[k]+edge[i].cost) { dis[edge[i].to]=dis[k]+edge[i].cost; if(!flag[edge[i].to]) q.push(edge[i].to); flag[edge[i].to]=1; from[edge[i].to]=i; } } } if(dis[ed]==inf) return 0; return dis[ed]; } int work(int st,int ed) { int pp=ed,ff=inf; while(pp!=st) { ff=min(ff,edge[from[pp]].w); pp=edge[from[pp]^1].to; } pp=ed; while(pp!=st) { edge[from[pp]].w-=ff; edge[from[pp]^1].w+=ff; pp=edge[from[pp]^1].to; } return ff; } int MCMF(int st,int ed) { int ret=0,l; while(l=spfa(st,ed)) ret+=work(st,ed)*l; return ret; } void work(){ pos(i,1,t){ add(S,i,cun[i],0); add(i,S,0,0); add(S,i+t,inf,p); add(i+t,S,0,-p); add(i+t,T,cun[i],0); add(T,i+t,0,0); if(i+m<=t){ add(i,i+m+t,inf,f); add(i+m+t,i,0,-f); } if(i+n<=t){ add(i,i+n+t,inf,s); add(i+n+t,i,0,-s); } if(i!=t){ add(i,i+1,inf,0); add(i+1,i,0,0); } } } int main(){ freopen("napkin.in","r",stdin); freopen("napkin.out","w",stdout); scanf("%d",&t); T=t*2+1; pos(i,1,t){ scanf("%d",&cun[i]); } scanf("%d%d%d%d%d",&p,&m,&f,&n,&s); work(); ans=MCMF(S,T); cout<<ans; return 0; }
最小费用最大流
欧拉函数线性筛
重要程度:★★★☆☆
熟练程度:★☆☆☆☆
貌似只会最暴力的求法
#include <iostream> #include <cstring> using namespace std; const int MAXN = 1000500; bool flag[MAXN];///标记数组 int phi[MAXN];///欧拉函数值,i的欧拉函数值=phi[i] int p[MAXN];///素因子的值 int cnt = 0; void Get_phi()///筛法求欧拉函数 { cnt = 0; memset(flag, true, sizeof(flag)); phi[1] = 1; for(int i=2; i<MAXN; i++)///线性筛法 { if(flag[i])///素数 { p[cnt++] = i; phi[i] = i-1;///素数的欧拉函数值是素数 - 1 } for(int j=0; j<cnt; j++) { if(i*p[j] > MAXN) break; flag[i*p[j]] = false;///素数的倍数,所以i*p[j]不是素数 if(i%p[j] == 0)///性质:i mod p == 0, 那么 phi(i * p) == p * phi(i) { phi[i*p[j]] = p[j] * phi[i]; break; } else phi[i*p[j]] = (p[j]-1) * phi[i];///i mod p != 0, 那么 phi(i * p) == phi(i) * (p-1) } } } int main() { Get_phi(); int m; while(cin>>m)///测试 { cout<<phi[m]<<endl; } return 0; }
欧拉函数线性筛
平衡树
重要程度:★★★★★
熟练程度:★★★☆☆
其重要性不言而喻,无奈码量太大
#include<iostream> #include<cstdio> #include<cstring> using namespace std; #define pos(i,a,b) for(int i=(a);i<=(b);i++) #define N 100000 int ch[N][3],size[N],w[N],v[N],fa[N]; int root,sz; void clear(int x){ ch[x][0]=ch[x][1]=fa[x]=w[x]=v[x]=size[x]=0; } int get(int x){ return ch[fa[x]][1]==x; } void update(int x){ if (x){ size[x]=w[x]; if (ch[x][0]) size[x]+=size[ch[x][0]]; if (ch[x][1]) size[x]+=size[ch[x][1]]; } } void rotate(int x){ int old=fa[x],oldf=fa[old],which=get(x); ch[old][which]=ch[x][which^1]; fa[ch[old][which]]=old; fa[old]=x;ch[x][which^1]=old; fa[x]=oldf; if (oldf) ch[oldf][ch[oldf][1]==old]=x; update(old);update(x); } void splay(int x){ for (int f;(f=fa[x]);rotate(x)) if (fa[f]) rotate((get(x)==get(f)?f:x)); root=x; } void insert(int x){ if(!root){ sz++;ch[sz][0]=ch[sz][1]=fa[sz]=0; size[sz]=w[sz]=1; v[sz]=x; root=sz; return; } int now=root,f=0; while(1){ if(v[now]==x){ w[now]++; update(now);update(f); splay(now); break; } f=now;now=ch[now][v[now]<x]; if(!now){ sz++; ch[sz][0]=ch[sz][1]=0; v[sz]=x;w[sz]=1;fa[sz]=f; ch[f][v[f]<x]=sz; update(f); splay(sz); break; } } } int find(int x){ int ans=0,now=root; while(1){ if(x<v[now]){ now=ch[now][0]; } else{ ans+=(ch[now][0]?size[ch[now][0]]:0); if(x==v[now]){ splay(now); return ans+1; } ans+=w[now]; now=ch[now][1]; } } } int findx(int x){ int now=root; while(1){ if(ch[now][0]&&x<=size[ch[now][0]]){ now=ch[now][0]; } else{ int temp=(ch[now][0]?size[ch[now][0]]:0)+w[now]; if(x<=temp) return v[now]; x-=temp; now=ch[now][1]; } } } int pre(){ int now=ch[root][0]; while(ch[now][1]) now=ch[now][1]; return now; } void del(int x){ int whatever=find(x); if(w[root]>1){ w[root]--; return; } if(!ch[root][0]&&!ch[root][1]){ clear(root); root=0; return; } if(!ch[root][0]){ int oldroot=root; root=ch[root][1]; fa[root]=0; clear(oldroot); return; } else{ if(!ch[root][1]){ int oldroot=root; root=ch[root][0]; fa[root]=0; clear(oldroot); return; } } int leftbig=pre(),oldroot=root; splay(leftbig); fa[ch[oldroot][1]]=root; ch[root][1]=ch[oldroot][1]; clear(oldroot); update(root); return; } int next(){ int now=ch[root][1]; while(ch[now][0]) now=ch[now][0]; return now; } int main(){ freopen("phs.in","r",stdin); freopen("phs.out","w",stdout); int n,opt,x; scanf("%d",&n); for (int i=1;i<=n;++i){ scanf("%d%d",&opt,&x); switch(opt){ case 1: insert(x); break; case 2: del(x); break; case 3: printf("%d\n",find(x)); break; case 4: printf("%d\n",findx(x)); break; case 5: insert(x); printf("%d\n",v[pre()]); del(x); break; case 6: insert(x); printf("%d\n",v[next()]); del(x); break; } } return 0; }
Splay伸展树
#include<iostream> #include<cstdlib> #include<cstdio> #include<cstring> using namespace std; #define pos(i,a,b) for(int i=(a);i<=(b);i++) #define pos2(i,a,b) for(int i=(a);i>=(b);i--) #define N 501000 struct Treep{ int l,r,w,v,size,rnd; }tree[N]; int n; int root,size; void update(int k){ tree[k].size=tree[tree[k].l].size+tree[tree[k].r].size+tree[k].w; } void lturn(int &k){ int t=tree[k].r; tree[k].r=tree[t].l; tree[t].l=k; tree[t].size=tree[k].size; update(k); k=t; } void rturn(int &k){ int t=tree[k].l; tree[k].l=tree[t].r; tree[t].r=k; tree[t].size=tree[k].size; update(k); k=t; } void insert(int &k,int x){ if(k==0){ size++; k=size; tree[k].w=tree[k].size=1; tree[k].v=x; tree[k].rnd=rand(); return; } tree[k].size++; if(tree[k].v==x) tree[k].w++; else{ if(tree[k].v<x){ insert(tree[k].r,x); if(tree[tree[k].r].rnd<tree[k].rnd) lturn(k); } else{ insert(tree[k].l,x); if(tree[tree[k].l].rnd<tree[k].rnd) rturn(k); } } } int tmp; void query_pro(int k,int x){ if(k==0) return; if(tree[k].v<x){ tmp=k; query_pro(tree[k].r,x); } else query_pro(tree[k].l,x); } void query_sub(int k,int x){ if(k==0) return; if(tree[k].v>x){ tmp=k; query_sub(tree[k].l,x); } else query_sub(tree[k].r,x); } void del(int &k,int x){ if(k==0) return; if(tree[k].v==x){ if(tree[k].w>1){ tree[k].w--; tree[k].size--; return; } if(tree[k].l*tree[k].r==0) k=tree[k].l+tree[k].r; else{ if(tree[tree[k].l].rnd<tree[k].rnd){ rturn(k); del(k,x); } else{ lturn(k); del(k,x); } } } else{ if(tree[k].v<x){ tree[k].size--; del(tree[k].r,x); } else{ tree[k].size--; del(tree[k].l,x); } } } int query_rank(int k,int x){ if(k==0) return 0; if(tree[k].v==x) return tree[tree[k].l].size+1; else{ if(tree[k].v<x) return tree[tree[k].l].size+tree[k].w+query_rank(tree[k].r,x); else return query_rank(tree[k].l,x); } } int query_num(int k,int x){ if(k==0) return 0; if(tree[tree[k].l].size>=x) return query_num(tree[k].l,x); else{ if(tree[tree[k].l].size+tree[k].w<x) return query_num(tree[k].r,x-tree[tree[k].l].size-tree[k].w); else return tree[k].v; } } int main() { freopen("phs.in","r",stdin); freopen("phs.out","w",stdout); scanf("%d",&n); int opt,x; pos(i,1,n){ scanf("%d%d",&opt,&x); switch(opt){ case 1:insert(root,x);break; case 2:del(root,x);break; case 3:printf("%d\n",query_rank(root,x));break; case 4:printf("%d\n",query_num(root,x));break; case 5:tmp=0;query_pro(root,x);printf("%d\n",tree[tmp].v);break; case 6:tmp=0;query_sub(root,x);printf("%d\n",tree[tmp].v);break; } } //while(1); return 0; }
Treap
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #define inf 0x7fffffff using namespace std; #define pos(i,a,b) for(int i=(a);i<=(b);i++) struct Treap{ Treap *ch[2]; int key,val,size; Treap(int v){ size=1;val=v;key=rand();ch[0]=ch[1]=NULL; } void tain(){ size=1+(ch[0]?ch[0]->size:0)+(ch[1]?ch[1]->size:0); } }*root; typedef pair<Treap*,Treap*> D; int size(Treap *o){ return o?o->size:0; } Treap *merge(Treap *a,Treap *b){ if(!a) return b; if(!b) return a; if(a->key < b->key){ a->ch[1]=merge(a->ch[1],b);a->tain();return a; } else{ b->ch[0]=merge(a,b->ch[0]);b->tain();return b; } } D split(Treap *o,int k){ if(!o) return D(NULL,NULL); D y; if(size(o->ch[0])>=k){ y=split(o->ch[0],k);o->ch[0]=y.second;o->tain();y.second=o; } else{ y=split(o->ch[1],k-size(o->ch[0])-1); o->ch[1]=y.first; o->tain(); y.first=o; } return y; } int getkth(Treap *o,int v){ if(o==NULL) return 0; return (o->val >= v)?getkth(o->ch[0],v):getkth(o->ch[1],v)+size(o->ch[0])+1; } int findkth(int k){ D x=split(root,k-1); D y=split(x.second,1); Treap *ans=y.first; root=merge(merge(x.first,ans),y.second); return ans!=NULL?ans->val:0; } void insert(int v){ int k=getkth(root,v); D x=split(root,k); Treap *o=new Treap(v); root=merge(merge(x.first,o),x.second); } void del(int v){ int k=getkth(root,v); D x=split(root,k); D y=split(x.second,1); root=merge(x.first,y.second); } int main(){ freopen("phs.in","r",stdin); freopen("phs.out","w",stdout); int m,opt,x;scanf("%d",&m); while(m--) { scanf("%d%d",&opt,&x); switch(opt) { case 1:insert(x);break; case 2:del(x);break; case 3:printf("%d\n",getkth(root,x)+1);break; case 4:printf("%d\n",findkth(x));break; case 5:printf("%d\n",findkth(getkth(root,x)));break; case 6:printf("%d\n",findkth(getkth(root,x+1)+1));break; } } return 0; }
无旋Treap
Graham扫描
重要程度:★☆☆☆☆
熟练程度:☆☆☆☆☆
这什么玩意。。好像联赛也不考
#include<iostream> #include<cstdio> #include<cstring> #include<vector> #include<cmath> #include<algorithm> using namespace std; #define pos(i,a,b) for(long long i=(a);i<=(b);i++) #define LL long long #define eps 1e-8; struct haha{ double x,y; friend bool operator < (haha a,haha b){ return (a.x==b.x)?a.y<b.y:a.x<b.x; } friend haha operator - (haha a,haha b){ haha c; c.x=a.x-b.x;c.y=a.y-b.y; return c; } }cun[10010]; vector<haha> v; int s[10010],top; double pow2(double x){ return x*x; } double cross(haha a,haha b){ return a.x*b.y-b.x*a.y; } double dis(haha &a,haha &b){ return sqrt(pow2(a.x-b.x)+pow2(a.y-b.y)); } bool check(haha a,haha b,haha c){ return cross(b-a,c-a)>eps; } int n,flag[10010]; double ans; int main(){ freopen("fc.in","r",stdin); freopen("fc.out","w",stdout); scanf("%d",&n); pos(i,1,n){ scanf("%lf%lf",&cun[i].x,&cun[i].y); } sort(cun+1,cun+n+1); s[++top]=1;s[++top]=2; pos(i,3,n){ while(top>1&&!check(cun[s[top]],cun[i],cun[s[top-1]])) top--; s[++top]=i; } pos(i,1,top){ flag[s[i]]=1;v.push_back(cun[s[i]]); } top=0; s[++top]=n;s[++top]=n-1; for(int i=n-2;i>=1;i--){ while(top>1&&check(cun[s[top]],cun[s[top-1]],cun[i])){ top--; } s[++top]=i; } pos(i,1,top){ if(!flag[s[i]]) v.push_back(cun[s[i]]); } for(int i=0,s=v.size();i<s;i++) ans+=dis(v[i],v[(i+1)%s]); printf("%0.2lf",ans); return 0; }
Graham扫描
RMQ
重要程度:★☆☆☆☆
熟练程度:☆☆☆☆☆
我就没打过,全用的线段树
/* RMQ算法:用DP预处理 O(nlog(n))的复杂度,查询每次是O(1)的。 那么查询的时候对于任意一个区间 l -- r ,我们同样可以得到区间差值 len = (r - l + 1)。 那么我们这一用小于2^k<=len,的 k 把区间分成可以交叉的两部分l 到 l+2^(k)- 1, 到 r -(1<<k)+1 到 r 的两部分, 很easy的求解了。 01.int rmq(int l,int r) 02.{ 03. int k=0; 04. while((1<<(k+1))<=r-l+1) 05. k++; 06. //printf("%d %d %d %d\n",l,l+(1<<k),r-(1<<k)+1,r-(1<<k)+1+(1<<k)); 07. int ans1=max(mm[l][k],mm[r-(1<<k)+1][k]); 08. int ans2=min(mi[l][k],mi[r-(1<<k)+1][k]); 09. return ans1-ans2; 10.} */ #include<cstdio> #include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> using namespace std; int a[100001]; int n,m; int d[100001][110]; void RMQ_init() { for (int i=1;i<=n;++i) d[i][0]=a[i];//以第i个数字为起点长度为2^0的序列的最小值,肯定先是自己。。 for (int j=1;(1<<j)<=n;++j)//1<<J的意思是j*2; for (int i=1;i+(1<<j)-1<=n;++i)//i从1到i+2*j-1这个长度范围内,即分别求出每个ij的最小值。。 d[i][j]=min(d[i][j-1],d[i+(1<<(j-1))][j-1]); } int RMQ(int l,int r) { int k=0; while ((1<<(k+1))<=r-l+1) k++;//只要K+1小于这个查询序列的一半,就一直更新,因为要把序列从中间分开, return min(d[l][k],d[r-(1<<k)+1][k]); } int main(){ ios::sync_with_stdio(false); freopen("faithful.in","r",stdin); freopen("faithful.out","w",stdout); scanf("%d%d",&n,&m); for(int i=1;i<=n;++i){ scanf("%d",&a[i]); } RMQ_init(); for(int i=1;i<=m;++i){ int x,y; scanf("%d%d",&x,&y); printf("%d",RMQ(x,y)); } return 0; }
RMQ
Dijkstra最短路
重要程度:★★☆☆☆
熟练程度:★☆☆☆☆
全用的SPFA
#include<cstdio> #include<algorithm> #include<cmath> #include<cstdlib> #include<cstring> #include<queue> #include<iostream> using namespace std; int a[5000],dis[5000],r[5000]; bool v[5000]; int n,tot = 0,m,aa,bb; int xiao(int x,int y) { if(x>y) return y; else return x; } int read() { int su=0; char ch=getchar(); while(ch<‘0‘||ch>‘9‘) ch=getchar(); while(ch<=‘9‘&&ch>=‘0‘) { su=su*10+ch-‘0‘; ch=getchar(); } return su; } struct ddd { int q,dat; friend bool operator < (ddd a, ddd b) { return a.dat > b.dat; } }; priority_queue<ddd> que; struct jie { int in; int out; int quan,next; }c[5000]; ddd cc; void add(int x,int y, int z) { c[++tot].in = x; c[tot].out = y; c[tot].quan = z; c[tot].next = r[x]; r[x] = tot; } int dj(int u) { int x,y; cc.q = u; cc.dat = 0; que.push(cc); memset(dis,0x7f,sizeof(dis)); memset(v,0,sizeof(v)); dis[u] = 0; while (!que.empty()) { x=que.top().q; y=que.top().dat; que.pop(); if(!v[x]) { v[x] = true; for(int i=r[x];i;i=c[i].next) { cc.q = c[i].out; if(dis[cc.q]> y+c[i].quan) { dis[cc.q]=y+c[i].quan; cc.dat=dis[cc.q]; que.push(cc); } } } } } int main() { n=read();//个数 m=read();//线路 aa=read();//出发点 bb=read();//目标点 for(int i=1; i<=m; i++) { int x,y,z; x=read(); y=read(); z=read(); add(x,y,z); add(y,x,z); } dj(aa); cout<<dis[bb]; while(1); return 0; }
Dijkstra堆优化
SPFA
重要程度:★★★★★
熟练程度:★★★★★
非常之熟悉,保命的
void spfa(int x){ memset(dis,0x7f,sizeof(dis)); memset(flag,0,sizeof(flag)); queue<int> q; flag[x]=1;dis[x]=0;q.push(x); while(!q.empty()){ int k=q.front(); for(int i=head[k];i;i=edge[i].next){ int to=edge[i].to,w=edge[i].w; if(dis[to]>dis[k]+w){ dis[to]=dis[k]+w; if(!flag[to]){ flag[to]=1; q.push(to); } } } flag[q.front()]=0; q.pop(); } }
SPFA
并查集
重要程度:★★★★★
熟练程度:★★★★★
码量小,好理解,很熟悉
#include<iostream> #include<cstdio> #include<cmath> #include<queue> #include<algorithm> #include<cstring> using namespace std; int n,m,q; int father[20050]; int read() { int su=0; char ch=getchar(); while(ch<‘0‘||ch>‘9‘) ch=getchar(); while(ch<=‘9‘&&ch>=‘0‘) { su=su*10+ch-‘0‘; ch=getchar(); } return su; } int find(int x)//查找x的祖先 { if(father[x]!=x) father[x]=find(father[x]); return father[x]; } void hebing(int x,int y) { x=find(x); y=find(y); father[y]=x; } int main() { cin>>n>>m; //n个人,m种关系 for(int i=1;i<=n;i++) father[i]=i; for(int i=1;i<=m;i++) { int x,y; x=read();y=read(); hebing(x,y); } int p[n+10]; for(int i=1;i<=n;i++) { p[i]=find(i); } cin>>q; //q种询问 for(int i=1;i<=q;i++) { int x,y; x=read();y=read(); if(p[x]==p[y]) printf("Yes\n"); else printf("No\n"); } while(1); return 0; }
并查集
树状数组
重要程度:★★★★★
熟练程度:★★★★★
码量小,好理解,很熟悉
#include<iostream> #include<cstring> #include<string> #include<cstdio> using namespace std; int t; int ji=0; int a[50010]; int c[50010]; int n; int read() { int su=0; char ch=getchar(); while(ch<‘0‘||ch>‘9‘) ch=getchar(); while(ch<=‘9‘&&ch>=‘0‘) { su=su*10+ch-‘0‘; ch=getchar(); } return su; } int lowbit(int x) { return x&(-x); } void add(int i,int x) { while(i<=n) { c[i]+=x; i+=lowbit(i); } } int tot(int x) { int sum=0; while(x>0) { sum+=c[x]; x-=lowbit(x); } return sum; } int Sum(int i,int j) { return tot(j)-tot(i-1); } int main() { cin>>t; for(int i=1;i<=t;i++) { memset(a,0,sizeof(a)); memset(c,0,sizeof(c)); ji++; n=read(); for(int i=1;i<=n;i++) { a[i]=read(); add(i,a[i]); } printf("Case %d:\n",ji); //cout<<"Case "<<ji<<":"<<endl; char in[20]; while(1) { scanf("%s",in); if(in[0]==‘E‘) break; int x,y; x=read();y=read(); if(in[0]==‘Q‘) { printf("%d\n",Sum(x,y)); } if(in[0]==‘A‘) { a[x]+=y; add(x,y); } if(in[0]==‘S‘) { a[x]-=y; add(x,-y); } } } //while(1); return 0; }
树状数组
单调队列
重要程度:★★★★★
熟练程度:★★★★★
码量小,好理解,很熟悉,优化DP必备
#include<iostream> #include<cstdio> #include<cstring> using namespace std; #define pos(i,a,b) for(int i=(a);i<=(b);i++) #define pos2(i,a,b) for(int i=(a);i>=(b);i--) #define N 2500 int t,maxp,w; int in[N],out[N],inmoney[N],outmoney[N]; int f[N][N]; int q[N],mp[N]; int head,tail; int main() { memset(f,-50,sizeof(f)); scanf("%d%d%d",&t,&maxp,&w); pos(i,1,t) scanf("%d%d%d%d",&inmoney[i],&outmoney[i],&in[i],&out[i]); pos(i,1,w+1) f[i][0]=0; pos(i,1,w+1) pos(j,1,min(in[i],maxp)) f[i][j]=-inmoney[i]*j; pos(i,1,t) { pos(j,0,maxp) f[i][j]=max(f[i][j],f[i-1][j]); if(i>w+1) { int tian=i-w-1; head=tail=0;int temp; pos(j,0,maxp) { temp=f[tian][j]+j*inmoney[i]; while(head<tail&&q[tail-1]<temp) tail--; q[tail]=temp;mp[tail]=j; tail++; while(head<tail&&mp[head]+in[i]<j) head++; f[i][j]=max(f[i][j],q[head]-j*inmoney[i]); } head=tail=0; pos2(j,maxp,0) { temp=f[tian][j]+j*outmoney[i]; while(head<tail&&q[tail-1]<temp) tail--; q[tail]=temp;mp[tail]=j; tail++; while(head<tail&&mp[head]-out[i]>j) head++; f[i][j]=max(f[i][j],q[head]-j*outmoney[i]); } } } int ans=0; pos(i,1,t) pos(j,0,maxp) ans=max(ans,f[i][j]); cout<<ans; //while(1); return 0; }
单调队列优化DP
未完待续……
随着知识的学习还会有很多的模板要背,还会有很多的坑要填hhh