模板
java提交注意package #pragma comment(linker, "/STACK:1024000000,1024000000") kmp void Next(int n){ int j=0,k=-1; next[0]=-1; while(j<n){ if(k==-1||org[j]==org[k]){ j++;k++; if(org[j]!=org[k])next[j]=k; else next[j]=next[k]; } else k=next[k]; } return; } int search(int N,int n){//a为主串,b为模式串 int i=0,j=0; while(i<N&&j<n){ if(j==-1||a[i]==b[j]){i++;j++;} else j=next[j]; } if(j>=n)return i-n; else return -1; } 快速读入 /* 可以负数,不能小数*/ inline void inp( int &n ){ n=0; int ch=getchar_unlocked(),sign=1; while( ch < '0' || ch > '9' ){if(ch=='-')sign=-1; ch=getchar_unlocked();} while( ch >= '0' && ch <= '9' ) n=(n<<3)+(n<<1)+ ch-'0', ch=getchar_unlocked(); n=n*sign; } 树状数组 二维树状数组 /* 二维树状数组,low求低位,update向后更新,query查询 update(x,y,num):x、y横纵坐标,num加数 query(x,y):x,y横纵坐标,返回从1,1到x,y和,int范围 */ inline int low(int x){ return x&-x; } void update(int x,int y,int num){ int Y=y; while(x<=n){ y=Y; while(y<=n){ sum[x][y]+=num; y+=low(y); } x+=low(x); } } int query(int x,int y){ int Y=y,ans=0; while(x>0){ y=Y; while(y>0){ ans+=sum[x][y]; y-=low(y); } x-=low(x); } return ans; } 线段树 /*矩形周长,线段树*/ #define maxn 5005 #define lson l,m,rt<<1 #define rson m,r,rt<<1|1 struct Node{ int num,len,lnum,lazy; //num为此线段覆盖次数,len为覆盖长度,lnum为段数,lazy为延迟数 bool lc,rc; //表示线段两端有无被覆盖 }; struct Line{ int l,r,y; bool up; }; Line line[maxn<<1]; Node node[maxn<<2]; int num,x[maxn<<1]; void pushup(int rt){//向上更新 node[rt].len=node[rt<<1].len+node[rt<<1|1].len; node[rt].lnum=node[rt<<1].lnum+node[rt<<1|1].lnum; node[rt].lc=node[rt<<1].lc; node[rt].rc=node[rt<<1|1].rc; node[rt].num=max(node[rt<<1].num,node[rt<<1|1].num); if(node[rt<<1].rc&&node[rt<<1|1].lc) node[rt].lnum--;//如果左孩子的右节点和右孩子的左节点都被标记,则线段数减1 return; } void pushdown(int rt,int l,int r){//向下更新 if(node[rt].lazy){ int m=l+r>>1; node[rt<<1].len=x[m-1]-x[l-1]; node[rt<<1|1].len=x[r-1]-x[m-1]; node[rt<<1].num+=node[rt].lazy; node[rt<<1|1].num+=node[rt].lazy; node[rt<<1].lazy+=node[rt].lazy; node[rt<<1|1].lazy+=node[rt].lazy; if(node[rt<<1].num>0) node[rt<<1].lnum=node[rt<<1].lc=node[rt<<1].rc=1; else node[rt<<1].num=node[rt<<1].len=node[rt<<1].lnum=node[rt<<1].lc=node[rt<<1].rc=0; //如果覆盖数为0,则删除 if(node[rt<<1|1].num>0) node[rt<<1|1].lnum=node[rt<<1|1].lc=node[rt<<1|1].rc=1; else node[rt<<1|1].num=node[rt<<1|1].len=node[rt<<1|1].lnum=node[rt<<1|1].lc=node[rt<<1|1].rc=0; } node[rt].lazy=0; } void add(int L,int R,int l,int r,int rt){//增加线段 if(L<=l&&R>=r){ node[rt].len=x[r-1]-x[l-1]; node[rt].num++; node[rt].lc=node[rt].rc=node[rt].lnum=1; node[rt].lazy++;//延迟更新 return; } pushdown(rt,l,r); int m=(l+r)>>1; if(L<m)add(L,R,lson); if(R>m)add(L,R,rson); pushup(rt); return; } void del(int L,int R,int l,int r,int rt){//删除线段 if(L<=l&&R>=r){ node[rt].num--; if(node[rt].num<=0){ node[rt].len=0; node[rt].lc=node[rt].rc=node[rt].lnum=0; node[rt].num=0; node[rt].lazy--;//如果此线段被删除,延迟更新子线段 return; } if(r-l==1)return; } pushdown(rt,l,r); int m=(l+r)>>1; if(L<m)del(L,R,lson); if(R>m)del(L,R,rson); pushup(rt); return; } bool cmp(Line a,Line b){ if(a.y==b.y) return a.l<b.l; else return a.y<b.y; } inline int find(int key){//查询x坐标对应的下标,因为线段树要求从1开始,所以下标加1 return lower_bound(x,x+num,key)-x+1; } int main() { int n,i,x1,x2,y1,y2; scanf("%d",&n); num=0; for(i=0;i<n;i++){ scanf("%d%d%d%d",&x1,&y1,&x2,&y2); x[num++]=x1;x[num++]=x2; line[i<<1].l=x1;line[i<<1].r=x2;line[i<<1].y=y1;line[i<<1].up=1; line[i<<1|1].l=x1;line[i<<1|1].r=x2;line[i<<1|1].y=y2;line[i<<1|1].up=0; } sort(x,x+num);//对x排序,离散化处理 num=unique(x,x+num)-x;//去重 n=n<<1; sort(line,line+n,cmp); int pre=0,ans=0; for(i=0;i<n-1;i++){ if(line[i].up)//如果是下边,则加边 add(find(line[i].l),find(line[i].r),1,num,1); else //如果是上边,则删除 del(find(line[i].l),find(line[i].r),1,num,1); ans+=node[1].lnum*(line[i+1].y-line[i].y)*2;//平行y轴 ans+=abs(node[1].len-pre);//平行x轴 pre=node[1].len; } del(find(line[i].l),find(line[i].r),1,num,1); ans+=abs(node[1].len-pre); printf("%d\n",ans); } 无向图重联通分量 /** 无向图重联通分量 Tarjan n^2*/ stack<int> S; void dfs(int v,int f){ vis[v]=1; dph[v]=low[v]=d++; S.push(v); for(int i=0; i<org[v].size(); i++){ int u=org[v][i]; if(u==f)continue; if(vis[u]==1)low[v]=min(low[v],dph[u]); else if(!vis[u]){ dfs(u,v); low[v]=min(low[v],low[u]); if(low[u]>=dph[v]){//u为关节点 num++; belong[v].pb(num);belong[u].pb(num); while(S.top()!=u){// 注意边界,如果吧push放在for循环里就是!=v不用pop,否则就是!=u最后还要pop belong[S.top()].pb(num); S.pop(); } S.pop(); } } } vis[v]=2; } int Tarjan() //搜索重联通分量 { num=0; while(!S.empty())S.pop(); for(int i=1; i<=n; i++){ d=0; if(!vis[i]) dfs(i,-1); } } 最大流 Dinic /*Dinic n^2*m 当前弧+GAP*/ #define INF 999999999 #define maxm 900000 #define maxn 1000 int n,s,t,flow; struct edge{ int v,c,f,next; }e[maxm]; int first[maxn],cnt,cur[maxn],d[maxn],S,E;//S起点E终点 bool vis[maxn]; queue<int> q; inline void addedge( int u, int v, int w ){ e[cnt].v = v; e[cnt].c = w; e[cnt].f = 0;e[cnt].next = first[u]; first[u] = cnt++; e[cnt].v = u; e[cnt].c = 0; e[cnt].f = 0;e[cnt].next = first[v]; first[v] = cnt++; } int BFS() { int u,v; while ( !q.empty())q.pop(); q.push(S); memset(vis,0,sizeof(vis)); d[s] = 0; vis[s] = 1; while ( !q.empty() ) { u = q.front(); q.pop(); for ( int i = first[u]; ~i; i = e[i].next ) { v = e[i].v; if ( !vis[v] && e[i].c > e[i].f ) { vis[v] = 1; q.push(v); d[v] = d[u] + 1; } } } return vis[t]; } int DFS( int u, int a ) { if ( u == E || a == 0 ) return a; int fl = a,v,f; for ( int &i = cur[u]; ~i ; i = e[i].next ){ //i为cur[u]引用,当前弧优化 v = e[i].v; if ( d[u] + 1 == d[v] && ( f = DFS( v, min( a, e[i].c - e[i].f ) ) ) > 0 ) { e[i].f += f; e[i^1].f -= f; fl -= f; if ( !fl ) return a; } } return a-fl; } int dinic(int s,int e) { S=s;E=e; int flow=0; while ( BFS() ){ for ( int i = 1; i <= n; ++i ) cur[i] = first[i]; flow += DFS(s,INF); } return flow; } HLPP /*HLPP n^2*m^0.5 有GAP优化*/ #define Maxn 205 #define Maxm 160005 int first[Maxn],d[Maxn],cnt,re[Maxn]; int num[Maxn];//判断断层 int KN;//汇点可以到达的最大标号 bool vis[Maxn]; int S,E; queue<int> q; struct node { int ind; bool operator<(const node &a) const { return d[ind]<d[a.ind]; } node(int &x):ind(x) {} }; priority_queue<node> order; //HL优化效果不明显 struct edge { int v,c,f,next; } e[Maxm]; inline void add(int &a,int &b,int c){ e[cnt].v=b; e[cnt].c=c; e[cnt].f=0; e[cnt].next=first[a]; first[a]=cnt++; e[cnt].v=a; e[cnt].c=0; e[cnt].f=0; e[cnt].next=first[b]; first[b]=cnt++; } void init() { while(!q.empty())q.pop(); while(!order.empty())order.pop(); memset(vis,0,sizeof(vis)); memset(num,0,sizeof(num)); KN=E; vis[E]=vis[S]=1; d[E]=0; d[S]=E; q.push(E); int i,u,v; while(!q.empty()) { u=q.front(); q.pop(); for(i=first[u]; ~i; i=e[i].next) { v=e[i].v; if(!vis[v]) { d[v]=d[u]+1; num[d[v]]++; vis[v]=1; q.push(v); } } } memset(re,0,sizeof(re));memset(vis,0,sizeof(vis)); vis[S]=vis[E]=1; for(i=first[S]; ~i; i=e[i].next){ v=e[i].v; re[v]+=e[i].c; e[i].f=e[i].c; e[i^1].f=-e[i].c; if(!vis[v]) order.push(v); vis[v]=1; } } int deal(){ int u,v,Min,t,ii,f,i; while(!order.empty()) { u=order.top().ind; order.pop(); if(d[u]>KN)continue; //不关心可行流,只关心结果,因此不用退回 vis[u]=0; while(re[u]>0) { Min=1E9; for(i=first[u]; ~i; i=e[i].next){ if(e[i].c==e[i].f)continue; t=e[i].v; if(d[t]+1==d[u]){ v=t;ii=i;break; } else if(Min>d[t]) v=t,ii=i,Min=d[t]; } if(i==-1){ if(--num[d[u]]==0) KN=min(KN,d[u]-1); //出现断层,更新最大标号 d[u]=Min+1; } f=min(re[u],e[ii].c-e[ii].f); re[u]-=f; re[v]+=f; e[ii].f+=f; e[ii^1].f-=f; if(!vis[v])order.push(v); vis[v]=1; } } return re[E]; } int HLPP(int s,int e){ S=s;E=e; init(); return deal(); } 最小费用流 (Primal-Dual) /*最小费用流 (Primal-Dual) */ struct edge{ int cost, cap, v, next; }e[MAXM]; int first[MAXN], cnt; int vis[MAXN], d[MAXN]; int ans, cost, src, des, n; void init(){ memset(first, -1, sizeof(first)); cnt=ans=cost=0; } void add(int u, int v, int cap, int cost){ e[cnt].v = v; e[cnt].cap = cap; e[cnt].cost = cost; e[cnt].next = first[u]; first[u] = cnt++; e[cnt].v = u; e[cnt].cap = 0; e[cnt].cost = -cost; e[cnt].next = first[v]; first[v] = cnt++; } int aug(int u, int f){ if(u == des){ ans += cost * f; return f; } vis[u] = 1; int flow=f,t; for(int i = first[u]; ~i; i = e[i].next) if(e[i].cap && !e[i].cost && !vis[e[i].v]){ t = aug(edge[i].v, min(tmp,edge[i].cap)); edge[i].cap -= t; edge[i^1].cap += t; flow -= t; if(!flow) return f; } return f-flow; } deque<int>Q; bool modlabel(){ //SPFA 增广 for(int i = 0; i <= n; i++) d[i] = INF; d[des] = 0; whlie(!Q.empty())Q.pop(); Q.push_back(des); while(!Q.empty()){ int u = Q.front(), tmp; Q.pop_front(); for(int i = first[u]; ~i ; i = e[i].next) if(e[i^1].cap && (tmp = d[u] - e[i].cost) < d[e[i].v]) (d[e[i].v] = tmp) <= d[Q.empty() ? src : Q.front()] ? Q.push_front(e[i].v) : Q.push_back(e[i].v); } for(int u = 1; u <= n; u++) for(int i = first[u]; i != -1; i = e[i].next) e[i].cost += d[e[i].v] - d[u]; cost += d[src]; return d[src] < INF; } void costflow(){ while(modlabel()){ do memset(vis, 0, sizeof(vis)); while(aug(src, INF)); } } Zwk 适合最终流量大 费用范围不大 或增广路短的图 非负权值 /*zwk KM重标号 增广路同上,sap 不能用于负权值路*/ bool modlabel(){ int delta = INF; for(int u = 1; u <= n; u++) if(vis[u]) for(int i = first[u]; ~i ; i = e[i].next) if(e[i].cap && !vis[e[i].v] && e[i].cost < delta) delta = e[i].cost; if(delta == INF) return false; for(int u = 1; u <= n; u++) if(vis[u]) for(int i = first[u]; ~i ; i = e[i].next) edge[i].cost -= delta, edge[i^1].cost += delta; cost += delta; return true; } void costflow() { do{ do memset(vis, 0, sizeof(vis)); while(aug(src, INF)); }while(modlabel()); } 最短路 SPFA /** 复杂度分析: 普通SPFA km kmax=n 不适合稠密图 一般为2 优先级队列 加入节点复杂度logn 节点数太多时适得其反,对于特殊数据速度略小于普通spfa 对于随机图效果很好 手动模拟SLF,LLL 复杂度低于优先级队列,最坏情况与普通SPFA持平 */ #define Maxn 100010//最大点数 #define Maxm 400010//最大边数,无向图要建双向边 int w[Maxm],u[Maxm],next[Maxm],cnt; int first[Maxn],havein[Maxn];//havin为入队次数 long long d[Maxn];//距离 int n; bool in[Maxn];//队中标志 inline void add(int vn,int un,int wn){//邻接表存储 u[cnt]=un;w[cnt]=wn;next[cnt]=first[vn];first[vn]=cnt++; } struct node{ int v,dd; node(int &a):v(a),dd(d[a]){}; bool operator< (const node& a)const{ return dd>a.dd; } }; priority_queue<node> q; //利用优先级队列SLF和LLL bool spfa(int s){ int i,now,ne,t; memset(in,0,sizeof(in)); memset(havein,0,sizeof(havein)); for(i=0;i<n;i++)d[i]=INF; //memset(d,0x3f,sizeof(d)); d[s]=0;in[s]=1;q.push(s); while(!q.empty()){ now=q.top().v;q.pop(); if(!in[now])continue; in[now]=0; for(i=first[now];~i;i=next[i]){ ne=u[i]; if(d[ne]<=(t=d[now]+w[i]))continue; d[ne]=t; in[ne]=1; q.push(ne); if(++havein[ne]>n)return 0;//判断有无负环 } } return 1;//返回1为正常,0为有负环 } #define M 200000 //手动模拟 int q[M]; bool spfa(int s){ int i,now,ne,t; memset(in,0,sizeof(in)); memset(havein,0,sizeof(havein)); memset(d,0x3f,sizeof(d)); int l,r,len;l=r=len=0; long long sum=0; d[s]=0;in[s]=havein[s]=1; q[r++]=s;len++; while(l!=r){ now=q[l++]; if(l==M)l=0; if(d[now]*len>sum){//LLL q[r++]=now; if(r==M)r=0; continue; } len--; sum-=d[now]; in[now]=0; for(i=first[now];~i;i=Next[i]){ ne=u[i]; if(d[ne]<=(t=d[now]+w[i]))continue; d[ne]=t; if(in[ne])continue; in[ne]=1; if(t<=d[q[l]]){ //SLF if(--l<0)l=M-1; q[l]=ne; } else{ q[r++]=ne; if(r==M)r=0; } len++; sum+=t; if(++havein[ne]>n)return 0; } } return 1;//返回1为正常,0为有负环 } void init()//边初始化 { cnt=0; memset(first,-1,sizeof(first)); } dijkstra /*dijkstra 复杂度M+NlgN*/ struct node { double dis; int v; node(int &a):v(a),dis(d[a]){} bool operator <(const node &b)const{ if(dis==b.dis)return n>b.n; return dis>b.dis;//注意符号!!这是降序排列 } }; priority_queue<node> q; void dijkstra(int s) { while(!q.empty())q.pop(); int i,x; memset(vis,0,sizeof(vis)); memset(d,0x3f,sizeof(d)); d[s]=0; q.push(s); while(!q.empty()){ x=q.top().v;q.pop(); if(now.dis!=dis[x]||vis[x])continue; vis[x]=1; for(i=1;i<=n;i++){ if(!vis[i]&&dis[i]>dis[x]+map[x][i]){ dis[i]=dis[x]+map[x][i]; q.push(i); } } } return; } 拓扑排序 /**拓扑排序 n^2 递归版 注意爆栈*/ int inq[Maxn]; int topo[Maxn],t;//topo为结果序列 bool dfs(int u){ inq[u]=-1;//正在队列中 for(int v=0;v<n;v++) if(G[u][v]){ //邻接矩阵 if(inq[v]<0)return 0;//存在有向环 else if(!inq[v]&&!dfs(v))return 0; } inq[u]=1;topo[--t]=u; return 1; } bool toposort(){ t=n; memset(inq,0,sizeof(inq)); for(int u=0;u<n;u++) if(!inq[u]&&!dfs(u))return 0; return 1; } /*循环版 需要统计入度*/ int in[Maxn];//节点入度 int st[Maxn],cnt;//记录入度为0的点栈 bool toposort(){ for(int i=n,now; i>=1; i--){ //节点数 if(cnt==0)return 0;//没有入度为0的节点 now=st[--cnt]; for(int nn=1; nn<=n; nn++) if(map[now][nn]&&(--in[nn])==0)st[cnt++]=nn; in[now]=i; ans[i]=now; } return 1; } 最大匹配 /** 二分图最大匹配:Hopcroft-Karp算法 复杂度:N^0.5 * M */ //对于要匹配的点 分为x集合的点,和y集合的点 int Mx[MAX],My[MAX];//那么这里的Mx[i]的值表示x集合中i号点的匹配点,My[j]的值就是y集合j点匹配的点 int dx[MAX],dy[MAX];//这里就是bfs找增广路用的数组 对于u-->v可达就有dy[v] = dx[u] + 1 int vis[MAX],dis;//辅助 queue<int>Q; bool bfs() //最短增广路 { int i ,v,u; dis = INF; while(!Q.empty())q.pop(); memset(dx,-1,sizeof(dx)); memset(dy,-1,sizeof(dy)); for(i = 0; i < m ;i ++) // 寻找x中未匹配的 if(Mx[i] == -1) Q.push(i),dx[i] = 0; while(!Q.empty()){ u = Q.front(); Q.pop(); if(dx[u] > dis) break; for(i = head[u]; i != -1; i = edge[i].next){ v = edge[i].to; if(dy[v] == -1){ dy[v] = dx[u] + 1; if(My[v] == -1) dis = dy[v]; else{ dx[My[v]] = dy[v] + 1; Q.push(My[v]); } } } } return dis != INF; } bool dfs(int u){ int v; for(int i = head[u]; i != -1; i = edge[i].next){ v = edge[i].to; if(!vis[v] && dy[v] == dx[u] + 1){ vis[v] = 1; if(My[v] != -1 && dy[v] == dis) continue; if(My[v] == -1 || dfs(My[v])){ Mx[u] = v; My[v] = u; return true; } } } return false; } int match(){ int ans = 0; memset(Mx,-1,sizeof(Mx)); memset(My,-1,sizeof(My)); while(bfs()){ memset(vis,0,sizeof(vis)); for(int u = 0; u < m; u ++) if(Mx[u] == -1 && dfs(u))//这里特别要注意,Mx[u] == -1 && dfs(u)先后顺序千万不能换,dfs之后Mx[u]就会变化 ans ++; } return ans; }