奇怪的模板总结(未完)
来源:互联网 发布:济宁预算软件 编辑:程序博客网 时间:2024/06/15 21:27
数据结构
栈
记录先进后出的信息,可用于拓扑排序,Tarjan,单调栈优化,Splay中的Pushdown记录节点……
Code
void Work(){ sta[++top]=x; x=sta[top--];}
队列
可记录先进先出的信息,用于单调队列优化,广搜等。
Code
void Work(){ queue <int> q; q.push(x); x=q.front(); q.pop();}
堆
父亲的值优于子树任意一个儿子,可动态维护整个序列中的最大最小值。
Code
struct QNode{ int x; bool operator < (const QNode &T)const{ return x<T.x; } };void Work(){ priority_queue <QNode> q; q.push(QNode(x)); T=q.top(); q.pop();}
可并堆(左偏树)
满足堆式存储,并且可以快速合并。
Code
struct Leftist_Tree{ int lc,rc; int val,npl;}tr[maxn];void init(){ tr[0].npl=-1; }int Merge(int a,int b){ if(!a) return b; if(!b) return a; if(tr[a].val<tr[b].val) swap(a,b); Pushdown(a); tr[a].rc=Merge(tr[a].rc,b); if(tr[tr[a].lc].npl<tr[tr[a].rc].npl) swap(tr[a].lc,tr[a].rc); tr[a].npl=tr[tr[a].lc].npl+1; return a; }
树状数组
利用位运算动态维护前缀和,可记录一些满足区间加减法的信息。
Code
int bit[maxn];void add(int x,int val){ for(int i=x;i<=n;i+=i&-i) bit[i]+=val;}int query(int x){ int res=0; for(int i=x;i;i-=i&-i) res+=bit[i]; return res;}
Splay
有双旋操作的二叉排序树,用于维护序列,维护凸包,维护元素大小关系……
Code
#define maxn 100000+5#define L(k) tr[tr[k].ch[0]]#define R(k) tr[tr[k].ch[1]]struct Splay_Tree{ int ch[2]; int key,mx,rev,tag,fa,sz; }tr[maxn];int stack[maxn],a[maxn];int top,root,cnt;void Update(int k){ tr[k].sz=L(k).sz+R(k).sz+1; tr[k].mx=max(L(k).mx,R(k).mx); tr[k].mx=max(tr[k].mx,tr[k].key);}void Pushdown(int k){ if(tr[k].tag){ if(tr[k].ch[0]) L(k).tag+=tr[k].tag,L(k).mx+=tr[k].tag,L(k).key+=tr[k].tag; if(tr[k].ch[1]) R(k).tag+=tr[k].tag,R(k).mx+=tr[k].tag,R(k).key+=tr[k].tag; } if(tr[k].rev){ swap(tr[k].ch[0],tr[k].ch[1]); if(tr[k].ch[0]) L(k).rev^=1; if(tr[k].ch[1]) R(k).rev^=1; } tr[k].rev=tr[k].tag=0;}void Rotate(int &k,int d){ int t=tr[k].ch[d^1]; if(tr[t].ch[d]) tr[tr[t].ch[d]].fa=k; tr[t].fa=tr[k].fa; tr[k].fa=t; tr[k].ch[d^1]=tr[t].ch[d]; tr[t].ch[d]=k; Update(k); Update(t); k=t;}void Splay(int &k,int x){ if(tr[k].ch[0]) Pushdown(tr[k].ch[0]); if(tr[k].ch[1]) Pushdown(tr[k].ch[1]); int d1=L(k).sz<x?1:0,t=tr[k].ch[d1]; if(!d1) x-=L(k).sz+1; if(x){ int d2=L(t).sz<x?1:0; if(!d2) x-=L(t).sz+1; if(x){ Splay(tr[t].ch[d2],x); if(d1==d2) Rotate(k,d1^1); else Rotate(tr[k].ch[d1],d1); } Rotate(k,d1^1); }}int rank(int k){ int res=L(k).sz+1; stack[++top]=k; while(tr[k].fa){ int p=tr[k].fa; stack[++top]=p; if(tr[p].ch[1]==k) res+=L(p).sz+1; k=p; } return res;}void Insert(int pos,int val){ Splay(root,pos+1); Splay(tr[root].ch[1],pos+1-L(root).sz); R(root).ch[0]=++cnt; tr[cnt].key=tr[cnt].mx=val; tr[cnt].fa=tr[root].ch[1]; tr[cnt].sz=1; Update(tr[root].ch[1]); Update(root);}void Delete(int l,int r){ //有必要需回收垃圾,开个stack存储剩余pos Splay(root,l); Splay(tr[root].ch[1],r+1-L(root).sz); R(root).ch[0]=0; Update(tr[root].ch[1]); Update(root);}void Reverse(int l,int r){ Splay(root,l); Splay(tr[root].ch[1],r+1-L(root).sz); int pos=R(root).ch[0]; if(!tr[pos].rev){ tr[pos].rev^=1; swap(tr[pos].ch[0],tr[pos].ch[1]); } Update(tr[root].ch[1]); Update(root);}int Build(int l,int r){ if(l>r) return 0; if(l==r){ tr[l].key=tr[l].mx=a[l]; tr[l].sz=1; return l; } int k=(l+r)>>1; tr[k].ch[0]=Build(l,k-1); tr[k].ch[1]=Build(k+1,r); Update(k);}
线段树
每个节点维护一个区间,每次修改最多访问logn个节点,注意lazy标记有两个或两个以上时要分清楚标记的先后顺序,科维护区间信息,维护连通性……
Code
#define maxn 200000+5typedef long long LL; struct Seg_Tree{ int l,r; int mx,tag; LL sum;}tr[maxn<<2];int tmp[maxn];void Update(int k){ tr[k].sum=tr[k<<1].sum+tr[k<<1|1].sum; tr[k].mx=max(tr[k<<1].mx,tr[k<<1|1].mx);}void Pushdown(int k){ int sz1=tr[k<<1].r-tr[k<<1].l+1; int sz2=tr[k<<1|1].r-tr[k<<1|1].l+1; if(tr[k].tag){ tr[k<<1].tag+=tr[k].tag; tr[k<<1|1].tag+=tr[k].tag; tr[k<<1].sum+=(LL)tr[k].tag*sz1; tr[k<<1|1].sum+=(LL)tr[k].tag*sz2; tr[k<<1].mx+=tr[k].tag; tr[k<<1|1].mx+=tr[k].tag; tr[k].tag=0; }}void Build(int k,int l,int r){ tr[k].l=l; tr[k].r=r; if(l==r){ tr[k].mx=tr[k].sum=tmp[l]; return; } int mid=(l+r)>>1; Build(k<<1,l,mid); Build(k<<1|1,mid+1,r); Update(k);}void Modify(int k,int l,int r,int val){ Pushdown(k); if(tr[k].l==l && tr[k].r==r){ tr[k].sum+=val*(r-l+1); tr[k].tag+=val; tr[k].mx+=val; return; } if(tr[k<<1].r>=r) Modify(k<<1,l,r,val); else if(tr[k<<1|1].l<=l) Modify(k<<1|1,l,r,val); else Modify(k<<1,l,tr[k<<1].r,val),Modify(k<<1|1,tr[k<<1|1].l,r,val); Update(k);}LL Query(int k,int l,int r){ Pushdown(k); if(tr[k].l==l && tr[k].r==r) return tr[k].sum; if(tr[k<<1].r>=r) return Query(k<<1,l,r); else if(tr[k<<1|1].l<=l) return Query(k<<1|1,l,r); else return Query(k<<1,l,tr[k<<1].r)+Query(k<<1|1,tr[k<<1|1].l,r);}
树链剖分
void dfs1(int x,int d){ sz[x]=1; dep[x]=d; son[x]=0; for(int i=V.head[x];i!=-1;i=V.nxt[i]){ dfs1(V.v[i],d+1); sz[x]+=sz[V.v[i]]; if(sz[V.v[i]]>sz[son[x]]) son[x]=V.v[i]; } }void dfs2(int x,int tp){ top[x]=tp; w[x]=++cnt; ord[cnt]=x; if(son[x]) dfs2(son[x],tp); for(int i=V.head[x];i!=-1;i=V.nxt[i]) if(V.v[i]!=son[x]) dfs2(V.v[i],V.v[i]); }int work(int x,int y){ // x为y父亲,否则需要每次找最深的向上回溯,知道其top相同 int res=0; for(;top[x]!=top[y];y=fa[top[y]]) res+=Query(1,w[top[y]],w[y],p); return res;}
主席树
如果n个节点中相邻两个节点的线段树差别不大时,我们可以考虑对每个节点都记录一个版本的线段树,相邻线段树直接的转移可以通过修改log n个节点得到。
Code
struct Seg_Tree{ int lc,rc; LL sum;}tr[maxn<<5];int root[maxn];void Insert(int last,int &k,int l,int r,int p,int val){ k=++tot; tr[k]=tr[last]; tr[k].sum+=val if(l==r) return; int mid=(l+r)>>1; if(p<=mid) Insert(tr[last].lc,tr[k].lc,l,mid,p,val); else Insert(tr[last].rc,tr[k].rc,mid+1,r,p,val);}LL Query(int k1,int k2,int l,int r,int p){ if(l==r) return tr[k2].sum-tr[k1].sum; int mid=(l+r)>>1; if(p<=mid) return Query(tr[k1].lc,tr[k2].lc,l,mid,p); else return Query(tr[k1].rc,tr[k2].rc,mid+1,r,p)+tr[tr[k2].lc].sum-tr[tr[k1].lc].sum;}void Modify(int x,int pos,int val){ for(int i=pos;i<=n;i+=i&-i) Insert(root[i],root[i],1,n,x,val);}
Link-Cut-Tree
类似于树链剖分,使用Splay等数据结构动态维护树的结构,支持Link,Cut等操作。
Code
struct Splay_Tree{ int ch[2]; int val,sz,fa,pf,rev;}tr[maxn];int stack[maxn],top;int rank(int k,int &rt){ int res=tr[tr[k].ch[0]].sz+1; stack[++top]=k; while(tr[k].fa){ int p=tr[k].fa; if(tr[p].ch[1]==k) res+=tr[tr[p].ch[0]].sz+1; stack[++top]=p; k=p; } rt=k; return res;}void Haha(int k){ int rt,x=rank(k,rt); while(top) Pushdown(stack[top--]); x=rank(k,rt); Splay(rt,x);}void Cutright(int k){ if(tr[k].ch[1]){ tr[tr[k].ch[1]].pf=k; tr[tr[k].ch[1]].fa=0; tr[k].ch[1]=0; Update(k); }}void Access(int k){ Haha(k); Cutright(k); for(int u;u;Update(u),k=u){ u=tr[k].pf; Haha(u); Cutright(u); tr[u].ch[1]=k; tr[k].pf=0; tr[k].fa=u; }}void Beroot(int k){ Access(k); Haha(k); tr[k].rev^=1;}int Find(int k){ Access(k); Haha(k); while(tr[k].ch[0]) k=tr[k].ch[0]; return k;}void Link(int x,int y){ int rt1=Find(x),rt2=Find(y); if(rt1==rt2) return; Beroot(x); Access(y); tr[x].pf=y;}void Cut(int x,int y){ Beroot(x); Access(y); Haha(y); tr[y].ch[0]=tr[x].pf=tr[x].fa=0; Update(y);}int Query(int x,int y){ Beroot(x); Access(y); Haha(y); return tr[y].val;}
图论
二分图匹配(匈牙利算法)
Code
int link[maxn],vis[maxn];bool match(int x){ for(int i=head[x];i!=-1;i=e[i].nxt) if(!vis[e[i].v]){ vis[e[i].v]=1; if(link[e[i].v]==-1 || match(link[e[i].v])){ link[e[i].v]=x; return true; } } return false;}
二分图带权匹配(KM)
//------------------未完待续1s----------------------
网络流
1. 最大流(Dinic)
BFS分层图标号,DFS增广(当前弧优化记录在当前分层图到过的边)
Code
struct Edge{ int u,v,cap; int nxt;}e[maxn<<2]; int lv[maxn],bow[maxn],head[maxn];int n,m,s,t,ans,ind;void addedge(int x,int y,int w){ e[ind]=(Edge){x,y,w,head[x]},head[x]=ind++; e[ind]=(Edge){y,x,0,head[y]},head[y]=ind++;}bool bfs(){ queue <int> q; memset(lv,0,sizeof(int)*(t+1)); lv[s]=1; q.push(s); while(!q.empty()){ int x=q.front(); q.pop(); for(int i=head[x];i!=-1;i=e[i].nxt) if(e[i].cap && !lv[e[i].v]){ lv[e[i].v]=lv[x]+1; q.push(e[i].v); } } return lv[t];}int dfs(int x,int t,int f){ if(x==t) return f; for(int &i=bow[x];i!=-1;i=e[i].nxt) if(e[i].cap && lv[e[i].v]>lv[x]){ int fff=dfs(e[i].v,t,min(e[i].cap,f)); if(fff){ e[i].cap-=fff; e[i^1].cap+=fff; return fff; } } return 0;}void dinic(){ while(bfs()){ memcpy(bow,head,sizeof(int)*(t+1)); while(true){ int fff=dfs(s,t,INF); if(fff) ans+=fff; else break; } }}
有上下界:转化为费用流,把边拆成两条,一条为(up-low,1),一条为(low,-INF),只需最后加上-INF的值即可。
2.费用流(SPFA)
用SPFA增广费用最小的边,记录沿途信息。
struct Edge{ int u,v,cap,w; int nxt;}e[maxn<<2];int pre[maxn],pre_e[maxn],dis[maxn],inq[maxn],head[maxn];int s,t,ans,ind;void addedge(int x,int y,int c,int w){ e[ind]=(Edge){x,y,c, w,head[x]},head[x]=ind++; e[ind]=(Edge){y,x,0,-w,head[y]},head[y]=ind++;}bool SPFA(){ queue <int> q; memset(dis,0x3f,sizeof(int)*(t+1)); dis[s]=0; q.push(s); while(!q.empty()){ int x=q.front(); q.pop(); inq[x]=0; for(int i=head[x];i!=-1;i=e[i].nxt) if(e[i].cap && dis[e[i].v]>dis[x]+e[i].w){ dis[e[i].v]=dis[x]+e[i].w; pre[e[i].v]=x; pre_e[e[i].v]=i; if(!inq[e[i].v]){ inq[e[i].v]=1; q.push(e[i].v); } } } return dis[t]!=INF;}void Costflow(){ while(SPFA()){ int fff=INF; for(int i=t;i!=s;i=pre[i]) fff=min(fff,e[pre_e[i]].cap); for(int i=t;i!=s;i=pre[i]){ e[pre_e[i]].cap-=fff; e[pre_e[i]^1].cap+=fff; } ans+=fff*dis[t]; }}
连通分量(Tarjan)
1.强连通分量
每次维护一个栈中标记、dfn(访问序号)、low(访问的最浅的节点)和一个栈。一个点的dfn==low从栈顶到这个点都是一个强连通分量。
Code
struct Edge{ int u,v; int nxt; }e[maxm];int head[maxn],stack[maxn],ins[maxn],dfn[maxn],low[maxn],d[maxn],sz[maxn];int top,n,cnt;void Tarjan(int x){ dfn[x]=low[x]=++cnt; stack[++top]=x; ins[x]=1; for(int i=head[x];i!=-1;i=e[i].nxt) if(!dfn[x]){ Tarjan(e[i].v); low[x]=min(low[x],low[e[i].v]); } else if(ins[e[i].v]) low[x]=min(low[x],dfn[e[i].v]); if(dfn[x]==low[x]){ int s; do{ s=stack[top--]; ins[s]=0; d[s]=x; sz[x]++; }while(s!=x); }}
2.双连通分量
1.点双连通分量:若一个dfs树上x子节点的low[son]>=low[x],那x为割点,注意特判根节点若超过1个儿子则不为割点。
2.边双连通分量:若一个dfs树上x子节点的low[son]>low[x],则这条边为桥。统计low的同时把边入栈,当找到一个割点时把栈里的边出栈,所有边上的点在一个边双连通分量里。
Code
struct Edge{ int u,v; int nxt;}e[maxn<<1];stack <Edge> s;bool cut[maxn];//cut[i]=true为割点int head[maxn],dfn[maxn],low[maxn],d[maxn],bcc[maxn][maxn],cutsum[maxn];int cnt,ind,tot,ans1;void Getbcc(int u,int v){//求边双连通分量 Edge E; cut[u]=true; bcc[++tot][0]=0; do{ E=s.top(); s.pop(); if(d[E.u]!=tot){ bcc[tot][++bcc[tot][0]]=E.u; d[E.u]=tot; } if(d[E.v]!=tot){ bcc[tot][++bcc[tot][0]]=E.v; d[E.v]=tot; } }while(E.u!=u || E.v!=v); }void Tarjan(int t,int p){ int chsum=0; dfn[t]=low[t]=++cnt; for(int i=head[t];i!=-1;i=e[i].nxt) if(p!=e[i].v){ if(!dfn[e[i].v]){ chsum++; s.push(e[i]); Tarjan(e[i].v,t); low[t]=min(low[t],low[e[i].v]); if(low[e[i].v]>=dfn[t]) Getbcc(t,e[i].v); } else if(dfn[e[i].v]<dfn[t]){ s.push(e[i]); low[t]=min(low[t],dfn[e[i].v]); } } if(p<0 && chsum==1) cut[t]=0;}
拓扑排序
每次把入度为0的节点放入到某数据结构中,并更新其他节点的入度。可用于判环,DP。
字符串
KMP
将匹配串与自身匹配求出next数组,再与模式串匹配。
Code
char s[maxn],t[maxn];int next[maxn];int lens,lent;void Getnext(){ next[0]=next[1]=0; for(int i=1,now=0;i<lent;i++){ while(t[i]!=t[now] && now) now=next[now]; if(t[i]==t[now]) now++; next[i+1]=now; }}void KMP(){ Getnext(); for(int i=0,now=0;i<lens;i++){ while(s[i]!=t[now] && now) now=next[now]; if(s[i]==t[now]) now++; if(now==lent) now=next[now]; }}
Trie树
后缀数组
维护每一个后缀的“字典序”排名和与前一个排名的后缀的LCP的长度。
每一个后缀的前缀都是原本字符串的一个子串。
Code
char ch[maxn];int sa[maxn],t1[maxn],t2[maxn],c[maxn];int rank[maxn],height[maxn];int len;bool cmp(int *r,int a,int b,int k){ return r[a]==r[b] && r[a+k]==r[b+k];}void DA(int n,int m){ int *x=t1,*y=t2; for(int i=0;i<m;i++) c[i]=0; for(int i=0;i<n;i++) c[x[i]=ch[i]]++; for(int i=1;i<m;i++) c[i]+=c[i-1]; for(int i=n-1;i>=0;i--) sa[--c[x[i]]]=i; for(int k=1;k<=n;k<<=1){ int p1=0,p2=1; for(int i=n-k;i<n;i++) y[p1++]=i; for(int i=0;i<n;i++) if(sa[i]>=k) y[p1++]=sa[i]-k; for(int i=1;i<m;i++) c[i]=0; for(int i=0;i<n;i++) c[x[y[i]]]++; for(int i=1;i<m;i++) c[i]+=c[i-1]; for(int i=n-1;i>=0;i--) sa[--c[x[y[i]]]]=y[i]; swap(x,y); x[sa[0]]=0; for(int i=1;i<n;i++) x[sa[i]]=cmp(y,sa[i-1],sa[i],k)?p2-1:p2++; if(p2>=n) return; m=p2; }}void Getheight(int n){ for(int i=0;i<=n;i++) rank[sa[i]]=i; for(int k=0,i=0;i<n;i++){ if(k) k--; int j=sa[rank[i]-1]; while(ch[i+k]==ch[j+k]) k++; height[rank[i]]=k; }}int main(){ scanf("%s",ch); len=strlen(ch); DA(len+1,128); Getheight(len); return 0; }
后缀自动机
#include<cstdio>#include<cstdlib>#include<cstring>#include<algorithm>#define maxn 20000+5using namespace std;struct SAM{ int am[maxn][26],mx[maxn],fa[maxn]; int last,cnt; SAM(){ last=cnt=1; } void extend(int c){ int p=last,np=++cnt; last=np; mx[np]=mx[p]+1; for(;p && !am[p][c];p=fa[p]) am[p][c]=np; if(!p) fa[np]=1; else{ int q=am[p][c]; if(mx[q]==mx[p]+1) fa[np]=q; else{ int nq=++cnt; memcpy(am[nq],am[q],sizeof(am[q])); mx[nq]=mx[p]+1; fa[nq]=fa[q]; fa[q]=fa[np]=nq; for(;p && am[p][c]==q;p=fa[p]) am[p][c]=nq; } } }}sam;char s[maxn];int len;int main(){ scanf("%s",s+1); len=strlen(s+1); for(int i=1;i<=len;i++) sam.extend(s[i]-'A'); return 0; }
字符串哈希
//------------------未完待续1s----------------------
马拉车
//------------------未完待续1s----------------------
数论
线性规划(单纯形法)
#include<cmath>#include<cstdio>#include<climits>#include<cstring>#include<cstdlib>#include<algorithm>#define maxn 1000+5#define maxm 10000+5#define INF (INT_MAX-1)using namespace std;const double eps=1e-7;double a[maxm][maxn],b[maxm],c[maxn];double ans;int n,m;void pivot(int l,int e){ b[l]/=a[l][e]; a[l][e]=1.0/a[l][e]; for(int i=1;i<=n;i++) if(i!=e) a[l][i]*=a[l][e]; //处理原等式 for(int i=1;i<=m;i++) if(i!=l && fabs(a[i][e])>eps){ b[i]-=a[i][e]*b[l]; for(int j=1;j<=n;j++) if(j!=e) a[i][j]-=a[l][j]*a[i][e]; a[i][e]=-a[l][e]*a[i][e]; } //代入其余等式 ans+=b[l]*c[e]; for(int i=1;i<=n;i++) if(i!=e) c[i]-=c[e]*a[l][i]; c[e]=-c[e]*a[l][e]; //代入目标函数}double Simplex(){ while(true){ int e=0,l=0; double tmp=INF; for(int i=1;i<=n;i++) if(c[i]>eps && c[i]>c[e]) e=i; //贪心加一波ans,快了两三倍 if(e==0) return ans; for(int i=1;i<=m;i++) if(a[i][e]>eps && tmp>b[i]/a[i][e]){ l=i; tmp=b[i]/a[i][e]; } if(tmp==INF) return INF; pivot(l,e); }}int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%lf",&c[i]); for(int l,r,i=1;i<=m;i++){ scanf("%d%d",&l,&r); for(int j=l;j<=r;j++) a[i][j]=1; scanf("%lf",&b[i]); } printf("%d",(int)(Simplex()+0.5)); return 0;}
- 奇怪的模板总结(未完)
- 存储系统总结(未完)
- java8总结(未完)
- 表单总结(未完)
- Eclipse使用总结(未完)
- JavaScript基础总结(未完)
- 计算机网络课程总结(未完)
- 2018考研总结(未完)
- 做RFID卡开门器的一些总结(未完)
- android5.1 AlarmManagerService的学习总结(未完)
- 数学符号的意义总结(未完待续)
- 部分简单数论模板(未完待续)
- 预告:奇怪的模板类友元语法
- .NET的MVC 初学总结-未完待续
- C++ Primer阅读总结(未完!)
- Ajax学习笔记总结(未完待续)
- C#---线程池学习总结(未完。。。。)
- Java常见异常总结(未完)
- ASP.NET的三层架构(DAL,BLL,UI)
- 注解配置AOP
- 你真的了解分层架构吗?——写给被PetShop"毒害"的朋友们
- 算法
- maven-tomcat-远程部署web项目
- 奇怪的模板总结(未完)
- java面试宝典超长完整版(续)
- RabbitMQ学习(一)-RabbitMQ安装
- redis源码--processTimeEvents时间事件
- Subsets
- java线程安全总结(一)
- Deep learning简介
- 线程安全总结(二)
- Using vs2015 64-bit compiler to build up CGAL-4.7 on window 7