---------------
一、模板
---
1、NGUNSTTD-PO
Name: NeverGiveUpNeverSurrenderTerribleTerribleDamage-PowerOverwhelmingUsage: Put it before main function
Tags: 头文件 循环 常用语句
---
/** head-file **/
#include <iostream>
#include <fstream>
#include <sstream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <vector>
#include <queue>
#include <stack>
#include <list>
#include <set>
#include <map>
#include <algorithm>
/** define-for **/
#define REP(i, n) for (int i=0;i<int(n);++i)
#define FOR(i, a, b) for (int i=int(a);i<int(b);++i)
#define DWN(i, b, a) for (int i=int(b-1);i>=int(a);--i)
#define REP_1(i, n) for (int i=1;i<=int(n);++i)
#define FOR_1(i, a, b) for (int i=int(a);i<=int(b);++i)
#define DWN_1(i, b, a) for (int i=int(b);i>=int(a);--i)
#define REP_N(i, n) for (i=0;i<int(n);++i)
#define FOR_N(i, a, b) for (i=int(a);i<int(b);++i)
#define DWN_N(i, b, a) for (i=int(b-1);i>=int(a);--i)
#define REP_1_N(i, n) for (i=1;i<=int(n);++i)
#define FOR_1_N(i, a, b) for (i=int(a);i<=int(b);++i)
#define DWN_1_N(i, b, a) for (i=int(b);i>=int(a);--i)
/** define-useful **/
#define clr(x,a) memset(x,a,sizeof(x))
#define sz(x) int(x.size())
#define see(x) cerr<<#x<<" "<<x<<endl
#define se(x) cerr<<" "<<x
#define pb push_back
#define mp make_pair
/** test **/
#define Display(A, n, m) { \
REP(i, n){ \
REP(j, m) cout << A[i][j] << " "; \
cout << endl; \
} \
}
#define Display_1(A, n, m) { \
REP_1(i, n){ \
REP_1(j, m) cout << A[i][j] << " "; \
cout << endl; \
} \
}
using namespace std;
/** typedef **/
typedef long long LL;
/** Add - On **/
const int direct4[4][2]={ {0,1},{1,0},{0,-1},{-1,0} };
const int direct8[8][2]={ {0,1},{1,0},{0,-1},{-1,0},{1,1},{1,-1},{-1,1},{-1,-1} };
const int direct3[6][3]={ {1,0,0},{0,1,0},{0,0,1},{-1,0,0},{0,-1,0},{0,0,-1} };
const int MOD = 1000000007;
const int INF = 0x3f3f3f3f;
const long long INFF = 1LL << 60;
const double EPS = 1e-9;
const double OO = 1e15;
const double PI = acos(-1.0); //M_PI;
---
---------------
二、图论
---
1 建图
---
const int maxn=111111;
const int maxm=511111;
int n,m;
struct EDGENODE{
int to;
int w;
int next;
};
struct SGRAPH{
int head[maxn];
EDGENODE edges[maxm];
int edge;
void init()
{
clr(head,-1);
edge=0;
}
void addedge(int u,int v,int c=0)
{
edges[edge].w=c,edges[edge].to=v,edges[edge].next=head[u],head[u]=edge++;
}
}solver;
---
2 最短路
---
2.1 堆优化的dijkstra
---
const int maxn=11111;
const int maxm=1111111;
struct EdgeNode{
int to;
int w;
int next;
};
struct HeapNode{
int d,u;
bool operator<(const HeapNode& rhs) const{
return d>rhs.d;
}
};
struct Dijkstra{
EdgeNode edges[maxm];
int head[maxn];
int edge,n;
void init(int n){
this->n=n;
memset(head,-1,sizeof(head));
edge=0;
}
void addedges(int u,int v,int c){
edges[edge].w=c,edges[edge].to=v,edges[edge].next=head[u],head[u]=edge++;
}
bool done[maxn];
int dis[maxn];
int pre[maxn];
void dijkstra(int s){
priority_queue<HeapNode>que;
for (int i=0;i<n;i++) dis[i]=INF;
dis[s]=0;
memset(done,0,sizeof(done));
que.push((HeapNode){0,s});
while (!que.empty()){
HeapNode x=que.top();
que.pop();
int u=x.u;
if (done[u]) continue;
done[u]=true;
for (int i=head[u];i!=-1;i=edges[i].next){
int v=edges[i].to;
int w=edges[i].w;
if (dis[v]>dis[u]+w){
dis[v]=dis[u]+w;
pre[v]=u;
que.push((HeapNode){dis[v],v});
}
}
}
}
}solver;
---
2.2 队列优化的Bellman-Ford
---
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <string>
#include <vector>
#include <cmath>
#include <queue>
using namespace std;
const int INF=0x3f3f3f3f;
const int maxm=111111;
const int maxn=11111;
struct EdgeNode{
int to;
int w;
int next;
};struct BellmanFord{
EdgeNode edges[maxm];
int head[maxn],edge,n;
bool vis[maxn];
int outque[maxn];
queue<int>que;
int dis[maxn];
void addedge(int u,int v,int c){
edges[edge].w=c,edges[edge].to=v,edges[edge].next=head[u],head[u]=edge++;
}
void init(int n){
memset(head,-1,sizeof(head));
edge=0;
this->n=n;
}
bool spfa(int s){
int u;
for (int i=0;i<=n;i++) dis[i]=INF;
memset(vis,0,sizeof(vis));
memset(outque,0,sizeof(outque));
while (!que.empty()) que.pop();
que.push(s);
vis[s]=true;
dis[s]=0;
while (!que.empty()){
u=que.front();
que.pop();
vis[u]=false;
outque[u]++;
if (outque[u]>n) return false;
for (int i=head[u];i!=-1;i=edges[i].next){
int v=edges[i].to;
int w=edges[i].w;
if (dis[v]==INF||dis[v]>dis[u]+w){
dis[v]=dis[u]+w;
if (!vis[v]){
vis[v]=true;
que.push(v);
}
}
}
}
return true;
}
};
---
3 连通性
---
3.1 强连通分量Tarjan模板
---
const int maxn=111111;
const int maxm=511111;
int n,m;
struct EDGENODE{
int to;
int w;
int next;
};
struct SGRAPH{
int head[maxn];
EDGENODE edges[maxm];
int edge;
void init(int n)
{
clr(head,-1);
edge=0;
}
void addedge(int u,int v,int c=0)
{
edges[edge].w=c,edges[edge].to=v,edges[edge].next=head[u],head[u]=edge++;
}
int pre[maxn],lowlink[maxn],sccno[maxn],scc_cnt,dfs_clock;
stack<int>stk;
void dfs(int u)
{
pre[u]=lowlink[u]=++dfs_clock;
stk.push(u);
for (int i=head[u];i!=-1;i=edges[i].next){
int v=edges[i].to;
if (!pre[v]){
dfs(v);
lowlink[u]=min(lowlink[u],lowlink[v]);
} else if (!sccno[v]){
lowlink[u]=min(lowlink[u],pre[v]);
}
}
if (lowlink[u]==pre[u]){
scc_cnt++;
int x;
do{
x=stk.top();
stk.pop();
sccno[x]=scc_cnt;
}while (x!=u);
}
}
void find_scc(int n)
{
dfs_clock=scc_cnt=0;
clr(sccno,0);
clr(pre,0);
while (!stk.empty()) stk.pop();
REP(i,n) if (!pre[i]) dfs(i);
}
}solver;
---
3.2 双连通模板
---
const int maxn=1111;
const int maxm=5111;
int n,m;
struct EDGENODE{
int to;
int w;
bool cut;
int next;
};
struct SEDGE{
int u;
int v;
SEDGE(int uu=0,int vv=0){u=uu;v=vv;}
};
struct BCC_GRAPH{
int head[maxn];
EDGENODE edges[maxm];
int edge;
void init()
{
clr(head,-1);
edge=0;
}
void addedge(int u,int v,int c=0)
{
edges[edge].cut=0,edges[edge].w=c,edges[edge].to=v,edges[edge].next=head[u],head[u]=edge++;
}
//BCC_Tarjan
int dfn[maxn],low[maxn],bccno[maxn],dfs_clock,bcc_cnt;
bool iscut[maxn];
vector<int>bcc[maxn];
stack<SEDGE>stk;
int dfs(int u,int fa)
{
int lowu=dfn[u]=++dfs_clock;
int child=0;
for (int i=head[u];i!=-1;i=edges[i].next)
{
int v=edges[i].to;
if (v==fa) continue;
SEDGE e=SEDGE(u,v);
if (!dfn[v])
{
stk.push(e);
child++;
int lowv=dfs(v,u);
lowu=min(lowu,lowv);
if (dfn[u]<=lowv) //cut 割点
{
iscut[u]=true;
//done 点双连通
bcc_cnt++;
bcc[bcc_cnt].clear();
SEDGE x;
do{
x=stk.top();
stk.pop();
if (bccno[x.u]!=bcc_cnt)
{
bcc[bcc_cnt].push_back(x.u);
bccno[x.u]=bcc_cnt;
}
if (bccno[x.v]!=bcc_cnt)
{
bcc[bcc_cnt].push_back(x.v);
bccno[x.v]=bcc_cnt;
}
}while (x.u!=u||x.v!=v);
//over
}
if (dfn[u]<lowv) //cut 桥
{
edges[i].cut=true;
edges[i^1].cut=true;
}
}
else if (dfn[v]<dfn[u])
{
stk.push(e);//done
lowu=min(lowu,dfn[v]);
}
}
if (fa<0&&child==1) iscut[u]=0;
low[u]=lowu;
return lowu;
}
void find_bcc(int n)
{
while (!stk.empty()) stk.pop();
clr(dfn,0);
clr(iscut,0);
clr(bccno,0);
dfs_clock=bcc_cnt=0;
REP_1(i,n)
{
if (!dfn[i]) dfs(i,-1);
}
}
//another
int block[maxn];
int vis[maxn];
int b_num;
void b_dfs(int u)
{
vis[u]=true;
block[u]=b_num;
for (int i=head[u];i!=-1;i=edges[i].next)
{
if (edges[i].cut) continue;
int v=edges[i].to;
if (!vis[v]) b_dfs(v);
}
}
void find_block(int n)
{
//find_block 边双连通
clr(block,0);
clr(vis,0);
b_num=0;
REP_1(i,n)
{
if (!vis[i])
{
b_num++;
b_dfs(i);
}
}
}
}solver;
---
4 2-SAT
---
4.1 TwoSAT模板
---
const int maxn=2111;
const int maxm=2111111;
int n,m;
struct EDGENODE{
int to;
int next;
};
struct TWO_SAT{
int head[maxn*2];
EDGENODE edges[maxm*2];
int edge;
int n;
bool mark[maxn*2];
int S[maxn*2],c;
void init(int n){
this->n=n;
clr(mark,0);
clr(head,-1);
edge=0;
}
void addedge(int u,int v){
edges[edge].to=v,edges[edge].next=head[u],head[u]=edge++;
}
// x = xval or y = yval
void add_clause(int x,int xval,int y,int yval){
x=x*2+xval;
y=y*2+yval;
addedge(x^1,y);
addedge(y^1,x);
}
void add_con(int x,int xval){
x=x*2+xval;
addedge(x^1,x);
}
bool dfs(int x){
if (mark[x^1]) return false;
if (mark[x]) return true;
mark[x]=true;
S[c++]=x;
for (int i=head[x];i!=-1;i=edges[i].next)
if (!dfs(edges[i].to)) return false;
return true;
}
bool solve(){
for (int i=0;i<n*2;i+=2)
if (!mark[i]&&!mark[i+1]){
c=0;
if (!dfs(i)){
while (c>0) mark[S[--c]]=false;
if (!dfs(i+1)) return false;
}
}
return true;
}
}TwoSAT;
---
4.2 强连通Tarjan高效2-SAT
---
const int maxn=11111;
const int maxm=2111111;
int n,m;
struct EDGENODE{
int to;
int next;
};
struct TWO_SAT{
int head[maxn*2];
EDGENODE edges[maxm*2];
int edge;
int n;
void init(int n){
this->n=2*n;
clr(head,-1);
edge=0;
}
void addedge(int u,int v){
edges[edge].to=v,edges[edge].next=head[u],head[u]=edge++;
}
// x = xval or y = yval
void add_clause(int x,int xval,int y,int yval){
x=x*2+xval;
y=y*2+yval;
addedge(x^1,y);
addedge(y^1,x);
}
//x=xval
void add_con(int x,int xval){
x=x*2+xval;
addedge(x^1,x);
}
//
void add_self(int x,int xval,int y,int yval){
x=x*2+xval;
y=y*2+yval;
addedge(x,y);
}
int pre[maxn],lowlink[maxn],sccno[maxn],scc_cnt,dfs_clock;
stack<int>stk;
void dfs(int u)
{
pre[u]=lowlink[u]=++dfs_clock;
stk.push(u);
for (int i=head[u];i!=-1;i=edges[i].next){
int v=edges[i].to;
if (!pre[v]){
dfs(v);
lowlink[u]=min(lowlink[u],lowlink[v]);
} else if (!sccno[v]){
lowlink[u]=min(lowlink[u],pre[v]);
}
}
if (lowlink[u]==pre[u]){
scc_cnt++;
int x;
do{
x=stk.top();
stk.pop();
sccno[x]=scc_cnt;
}while (x!=u);
}
}
void find_scc(int n)
{
dfs_clock=scc_cnt=0;
clr(sccno,0);
clr(pre,0);
while (!stk.empty()) stk.pop();
REP(i,n) if (!pre[i]) dfs(i);
}
bool solve(){
find_scc(n);
for (int i=0;i<n;i+=2){
if (sccno[i]==sccno[i^1]) return false;
}
return true;
}
}TwoSAT;
---
5 网络流
---
5.1 最大流模板Dinic
---
const int INF = 0x3f3f3f3f;
const int maxm=11111;
const int maxn=2222;
struct edgenode{
int to,flow,next;
};
struct Dinic {
int node,src,dest,edge;
int head[maxn],work[maxn],dis[maxn],q[maxn];
edgenode edges[maxm];
void prepare(int _node,int _src,int _dest){
node=_node,src=_src,dest=_dest;
memset(head,-1,sizeof(head));
edge=0;
}
void addedge(int u,int v,int c){
edges[edge].flow=c,edges[edge].to=v,edges[edge].next=head[u],head[u]=edge++;
edges[edge].flow=0,edges[edge].to=u,edges[edge].next=head[v],head[v]=edge++;
}
bool Dinic_bfs() {
int i,u,v,l,r=0;
for (i=0; i<node; i++) dis[i]=-1;
dis[q[r++]=src]=0;
for (l=0; l<r; l++){
for (i=head[u=q[l]]; i!=-1; i=edges[i].next){
if (edges[i].flow&&dis[v=edges[i].to]<0){
dis[q[r++]=v]=dis[u]+1;
if (v==dest) return true;
}
}
}
return false;
}
int Dinic_dfs(int u,int exp){
if (u==dest) return exp;
for (int &i=work[u],v,tmp; i!=-1; i=edges[i].next){
if (edges[i].flow&&dis[v=edges[i].to]==dis[u]+1&&
(tmp=Dinic_dfs(v,min(exp,edges[i].flow)))>0){
edges[i].flow-=tmp;
edges[i^1].flow+=tmp;
return tmp;
}
}
return 0;
}
int Dinic_flow(){
int i,ret=0,delta;
while (Dinic_bfs()){
for (i=0; i<node; i++) work[i]=head[i];
while ( delta=Dinic_dfs(src,INF) ) ret+=delta;
}
return ret;
}
}solver;
---
5.2 最小费用最大流
---
const int INF=0x3f3f3f3f;//无穷大
const int maxm=1111111;//边的最大数量,为原图的两倍
const int maxn=2222;//点的最大数量
struct edgenode{
int to;//边的指向
int flow;//边的容量
int cost;//边的费用
int next;//链表的下一条边
};
struct MinCost{
edgenode edges[maxm];
int node,src,dest,edge;//node节点数,src源点,dest汇点,edge边数
int head[maxn],p[maxn],dis[maxn],q[maxn],vis[maxn];//head链表头,p记录可行流上节点对应的反向边,dis计算距离
void prepare(int _node=0,int _src=0,int _dest=0){
node=_node,src=_src,dest=_dest;
memset(head,-1,sizeof(head));
memset(vis,0,sizeof(vis));
edge=0;
}
void addedge(int u,int v,int f,int c){
printf("u=%d v=%d f=%d c=%d\n",u,v,f,c);
edges[edge].flow=f;edges[edge].cost=c;edges[edge].to=v;
edges[edge].next=head[u];head[u]=edge++;
edges[edge].flow=0;edges[edge].cost=-c;edges[edge].to=u;
edges[edge].next=head[v];head[v]=edge++;
}
bool spfa(){
int i,u,v,l,r=0,tmp;
for (i=0;i<node;i++) dis[i]=INF;
dis[q[r++]=src]=0;
p[src]=p[dest]=-1;
for (l=0;l!=r;((++l>=maxn)?l=0:l)){
for (i=head[u=q[l]],vis[u]=false;i!=-1;i=edges[i].next){
if (edges[i].flow&&dis[v=edges[i].to]>(tmp=dis[u]+edges[i].cost)){
dis[v]=tmp;
p[v]=i^1;
if (vis[v]) continue;
vis[q[r++]=v]=true;
if (r>=maxn) r=0;
}
}
}
return p[dest]>=0;
}
int spfaflow(){
int i,ret=0,delta;
while (spfa()){//按记录原路返回求流量
for (i=p[dest],delta=INF;i>=0;i=p[edges[i].to]){
delta=min(delta,edges[i^1].flow);
}
for (int i=p[dest];i>=0;i=p[edges[i].to]){
edges[i].flow+=delta;
edges[i^1].flow-=delta;
}
ret+=delta*dis[dest];
}
return ret;
}
void output(int u){
cout<<u<<endl;
for (int i=head[u];i!=-1;i=edges[i].next){
int v=edges[i].to;
if (edges[i].flow==0&&((i&1)==0)) output(v);
}
}
}solver;
-------------
6 无向图最小割 (New)
-----
struct StoerWagner{
int mat[maxn][maxn];
int dis[maxn];
int S,T;
int n;
bool vis[maxn],del[maxn];
void init(int n){
memset(mat,0,sizeof(mat));
this->n=n;
}
void addedge(int u,int v,int c){
mat[u][v]+=c;
mat[v][u]+=c;
}
int search(int ct){
int tmp,mx,cut;
memset(vis,0,sizeof(vis));
memset(dis,0,sizeof(dis));
T=S=-1;
for (int i=0;i<n-ct;i++){
mx=-1;
for (int j=0;j<n;j++){
if (!vis[j]&&!del[j]&&dis[j]>mx){
mx=dis[j];
tmp=j;
}
}
S=T;
T=tmp;
cut=mx;
vis[T]=true;
for (int j=0;j<n;j++){
if (!vis[j]&&!del[j]){
dis[j]+=mat[T][j];
}
}
}
return cut;
}
int minimumCut(){
int ans=INF;
memset(del,0,sizeof(del));
for (int i=0;i<n-1;i++){
int cut=search(i);
if (cut<ans) ans=cut;
if (ans==0) return 0;
del[T]=true;
for (int j=0;j<n;j++){
if (!del[j]){
mat[S][j]+=mat[T][j];
mat[j][S]+=mat[T][j];
}
}
}
return ans;
}
};
----------------------
7 倍增LCA
------------------------
void preprocess(){
for (int i=1;i<=n;i++){
anc[i][0]=fa[i];
maxCost[i][0]=cost[i];
for (int j=1;(1<<j)<n;j++) anc[i][j]=-1;
}
for (int j=1;(1<<j)<n;j++){
for (int i=1;i<=n;i++){
if (anc[i][j-1]!=-1){
int a=anc[i][j-1];
anc[i][j]=anc[a][j-1];
maxCost[i][j]=max(maxCost[i][j-1],maxCost[a][j-1]);
}
}
}
}
int query(int p,int q){
int log;
if (L[p]<L[q]) swap(p,q);
for (log=1;(1<<log)<=L[p];log++);log--;
int ans=-INF;
for (int i=log;i>=0;i--){
if (L[p]-(1<<i)>=L[q]){
ans=max(ans,maxCost[p][i]);
p=anc[p][i];
}
}
if (p==q) return ans;
for (int i=log;i>=0;i--){
if (anc[p][i]!=-1&&anc[p][i]!=anc[q][i]){
ans=max(ans,maxCost[p][i]);
p=anc[p][i];
ans=max(ans,maxCost[q][i]);
q=anc[q][i];
}
}
ans=max(ans,cost[p]);
ans=max(ans,cost[q]);
return ans;
}
8 树
8.1 树的重心
class CenterTree{
private:
int sz[maxn];
void dfs(int u,int pa){
sz[u]=1;
for (int i=head[u];i!=-1;i=edges[i].next){
int v=edges[i].to;
if (v==pa) continue;
//if (tree[v].visit) continue;
dfs(v,u);
sz[u]+=sz[v];
}
}
public:
int getCenter(int x){
int p=0;
dfs(x,p);
int cap=sz[x]/2;
bool found=true;
while (found){
found=false;
for (int i=head[x];i!=-1;i=edges[i].next){
int y=edges[i].to;
//if (tree[y].visit) continue;
if (y!=p&&sz[y]>cap){
found=true;
p=x;
x=y;
break;
}
}
}
return x;
}
}coder;
8.2 树的中心
class TreeCenter{
private:
int f[maxn];
int dp[maxn];
int M,MM;
int dfs(int u,int pa){
int m1=0,m2=0;
for (int i=head[u];i!=-1;i=edges[i].next){
int v=edges[i].to;
if (v==pa) continue;
int t=dfs(v,u);
if (t>m1){
m2=m1;
m1=t;
f[u]=i;
}
else if (t>m2){
m2=t;
}
}
if (M<m1+m2) MM=u,M=m1+m2;
dp[u]=m1;
return dp[u]+1;
}
public:
int getCenter(int n){
M=-1;
dfs(1,-1);
if (M&1){
while (dp[MM]*2>M+1) MM=edges[f[MM]].to;
//int E=f[MM];
addedge(MM,n+1);
addedge(n+1,MM);
addedge(edges[f[MM]].to,n+1);
addedge(n+1,edges[f[MM]].to);
MM=n+1;
}
else{
//int E=0;
while (dp[MM]*2>M) MM=edges[f[MM]].to;
}
return MM;
}
}solver;
---------------
三、数据结构
---
1 树堆Treap
---
名次树 启发式合并
#include <iostream>
#include <ctime>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <vector>
using namespace std;
struct Node{
Node* ch[2];//左右子树
int fix;//优先级。数值越大,优先级越高
int key;
int size;//以它为根的子树的总结点数
bool operator<(const Node& rhs) const {
return fix<rhs.fix;
}
int cmp(int x) const{
if (x==key) return -1;
return x<key?0:1;
}
//名次树
void maintain(){
size=1;
if (ch[0]!=NULL) size+=ch[0]->size;
if (ch[1]!=NULL) size+=ch[1]->size;
}
};
struct Treap{
Node* root;
Treap(){
srand(time(0));
root=NULL;
}
void removetree(Node* &t){
if (t->ch[0]!=NULL) removetree(t->ch[0]);
if (t->ch[1]!=NULL) removetree(t->ch[1]);
delete t;
t=NULL;
}
void clear(){
srand(time(0));
removetree(root);
}
Node* newNode(int v){
Node* t=new Node;
t->key=v;
t->ch[0]=t->ch[1]=NULL;
t->fix=rand();
t->size=1;
return t;
}
//d=0代表左旋,d=1代表右旋
void rotate(Node* &o,int d){
Node* k=o->ch[d^1];
o->ch[d^1]=k->ch[d];
k->ch[d]=o;
o->maintain();
k->maintain();
o=k;
}
//在以o为根的子树中插入键值x,修改o
void insert(Node* &o,int x){
if (o==NULL) o=newNode(x);
else{
int d=o->cmp(x);
if (d==-1) d=1;
insert(o->ch[d],x);
if (o->ch[d]>o) rotate(o,d^1);
}
o->maintain();
}
void remove(Node* &o,int x){
int d=o->cmp(x);
if (d==-1){
Node* u=o;
if (o->ch[0]!=NULL&&o->ch[1]!=NULL){
int d2=(o->ch[0]>o->ch[1]?1:0);
rotate(o,d2);
remove(o->ch[d2],x);
}else{
if (o->ch[0]==NULL) o=o->ch[1];
else if (o->ch[1]==NULL) o=o->ch[0];
delete u;
}
}
else remove(o->ch[d],x);
if (o!=NULL) o->maintain();
}
bool find(Node* o,int x){
while (o!=NULL){
int d=o->cmp(x);
if (d==-1) return 1;
else o=o->ch[d];
}
return 0;
}
//第k大的值
int kth(Node* o,int k){
if (o==NULL||k<=0||k>o->size) return 0;
int s=(o->ch[1]==NULL?0:o->ch[1]->size);
if (k==s+1) return o->key;
else if (k<=s) return kth(o->ch[1],k);
else return kth(o->ch[0],k-s-1);
}
void merge(Node* &src){
if (src->ch[0]!=NULL) merge(src->ch[0]);
if (src->ch[1]!=NULL) merge(src->ch[1]);
insert(root,src->key);
delete src;
src=NULL;
}
};
---
2 伸展树Splay
---
2.1 My Splay v1.0
---
/**********************************************************************************
Splay Tree v1.0 索引
Node:
void addIt(int ad) 区间添加ad
void revIt() 区间翻转
void upd() 更新结点,子树改变后使用
void pushdown() 向下传递懒惰标记
Splay:
Node* newNode(int v,Node* f) 构造一个val值为v的节点,父节点为f,
Node* build(int l,int r,Node* f) 构造区间[l,r],父节点为f;
void rotate(Node* t,int d) 左旋右旋
void splay(Node* t,Node* f) 将结点t伸展到f
void select(int k) 返回第k个节点并伸展到f,不计虚拟结点
Node*&get(int l, int r) 返回区间[l,r],即l-1旋转到根,r+1旋转到根的右儿子
void reverse(int l,int r) 翻转区间[l,r]
void split(int l,int r,Node*&s1) 将区间[l,r]剪切到s1
void cut(int l,int r) 将区间[l,r]剪切到序列尾部
void init(int n) 构造区间[1,n]并初始化
void show(Node* rt) 输出树rt的中序遍历,debug用
void output(int l,int r) 输出并伸展区间[l,r],复杂度较高待优化
注意:
每种修改操作(插入、删除、修改和翻转)过后,
要将修改的结点(即根结点右子结点的左子结点)Splay到根的位置。
删除操作要回收空间,可以人工压栈回收结点指针
**********************************************************************************/
#include <iostream>
#include <ctime>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <vector>
using namespace std;
const int MAX_N = 150000 + 10;
const int INF = ~0U >> 1;
struct Node{
Node *ch[2],*pre;//左右子树,父节点
int val;//关键字
int size;//以它为根的子树的总结点数
int mx;//最大值
int add;//添加标记
bool rev;//翻转标记
Node(){
size=0;
val=mx=-INF;
add=0;
}
void addIt(int ad){
add+=ad;
mx+=ad;
val+=ad;
}
void revIt(){
rev^=1;
}
void upd(){
size=ch[0]->size+ch[1]->size+1;
mx=max(val,max(ch[0]->mx,ch[1]->mx));
}
void pushdown();
}Tnull,*null=&Tnull;
void Node::pushdown(){
if (add!=0){
for (int i=0;i<2;++i)
if (ch[i]!=null) ch[i]->addIt(add);
add = 0;
}
if (rev){
swap(ch[0],ch[1]);
for (int i=0;i<2;i++)
if (ch[i]!=null) ch[i]->revIt();
rev = 0;
}
}
struct Splay{
Node nodePool[MAX_N],*cur;//内存分配
Node* root;//根
Splay(){
cur=nodePool;
root=null;
}
//清空内存,init()调用
void clear(){
cur=nodePool;
root=null;
}
//新建节点,build()用
Node* newNode(int v,Node* f){
cur->ch[0]=cur->ch[1]=null;
cur->size=1;
cur->val=v;
cur->mx=v;
cur->add=0;
cur->rev=0;
cur->pre=f;
return cur++;
}
//构造区间[l,r]中点m,init()使用
Node* build(int l,int r,Node* f){
if(l>r) return null;
int m=(l+r)>>1;
Node* t=newNode(m,f);
t->ch[0]=build(l,m-1,t);
t->ch[1]=build(m+1,r,t);
t->upd();
return t;
}
//旋转操作,c=0表示左旋,c=1表示右旋
void rotate(Node* x,int c){
Node* y=x->pre;
y->pushdown();
x->pushdown();
//先将y结点的标记向下传递(因为y在上面)
y->ch[!c]=x->ch[c];
if (x->ch[c]!=null) x->ch[c]->pre=y;
x->pre=y->pre;
if (y->pre!=null)
{
if (y->pre->ch[0]==y) y->pre->ch[0]=x;
else y->pre->ch[1]=x;
}
x->ch[c]=y;
y->pre=x;
y->upd();//维护y结点
if (y==root) root=x;
}
//Splay操作,表示把结点x转到结点f的下面
void splay(Node* x,Node* f){
x->pushdown();//下传x的标记
while (x->pre!=f){
if (x->pre->pre==f){//父节点的父亲为f,执行单旋
if (x->pre->ch[0]==x) rotate(x,1);
else rotate(x,0);
}else{
Node *y=x->pre,*z=y->pre;
if (z->ch[0]==y){
if (y->ch[0]==x) rotate(y,1),rotate(x,1);//一字型旋转
else rotate(x,0),rotate(x,1);//之字形旋转
}else{
if (y->ch[1]==x) rotate(y,0),rotate(x,0);//一字型旋转
else rotate(x,1),rotate(x,0);//之字形旋转
}
}
}
x->upd();//最后再维护X结点
}
//找到处在中序遍历第k个结点,并将其旋转到结点f的下面
void select(int k,Node* f){
int tmp;
Node* x=root;
x->pushdown();
k++;//空出虚拟节点
for(;;){
x->pushdown();
tmp=x->ch[0]->size;
if (k==tmp+1) break;
if (k<=tmp) x=x->ch[0];
else{
k-=tmp+1;
x=x->ch[1];
}
}
splay(x,f);
}
//选择[l,r]
Node*&get(int l, int r){
select(l-1,null);
select(r+1,root);
return root->ch[1]->ch[0];
}
//翻转[l,r]
void reverse(int l,int r){
Node* o=get(l,r);
o->rev^=1;
splay(o,null);
}
//剪切出[l,r]到s1
void split(int l,int r,Node*&s1)
{
Node* tmp=get(l,r);
s1=tmp;
root->ch[1]->ch[0]=null;
splay(root->ch[1],null);
}
void cut(int l,int r)
{
Node* tmp;
split(l,r,tmp);
select(root->size-1,null);
select(root->size-2,root);
root->ch[0]->ch[1]=tmp;
tmp->pre=root->ch[0];
splay(tmp,null);
}
//初始化
void init(int n){
clear();
root=newNode(0,null);
root->ch[1]=newNode(n+1,root);
root->ch[1]->ch[0]=build(1,n,root->ch[1]);
splay(root->ch[1]->ch[0],null);
}
//输出中序遍历,debug用
void show(Node* rt){
if (rt==null) return;
if (rt->ch[0]!=null) show(rt->ch[0]);
cerr<<"rt="<<rt->val;
if (rt->ch[0]!=null) cerr<<" l="<<rt->ch[0]->val;
if (rt->ch[1]!=null) cerr<<" r="<<rt->ch[1]->val;
if (rt->pre !=null) cerr<<" pre="<<rt->pre->val;
cerr<<endl;
if (rt->ch[1]!=null) show(rt->ch[1]);
}
//按序输出
void output(int l,int r){
for (int i=l;i<=r;i++){
select(i,null);
cout<<root->val<<endl;
}
//cout<<endl;
}
}T;
int main()
{
int n,m,a,b;
while (~scanf("%d%d",&n,&m))
{
T.init(n);
while (m--)
{
scanf("%d%d",&a,&b);
if (b<a) swap(a,b);
T.reverse(a,b);
T.cut(a,b);
}
T.output(1,n);
}
return 0;
}
---
2.2 BYVoid's Splay
---
/*
* Problem: NOI2005 sequence
* Author: Guo Jiabao
* Time: 2009.5.30 14:19
* State: Solved
* Memo: 伸展树
*/
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
using namespace std;
const int MAXN=2850003,MAXL=500001,INF=1001;
struct SplayTree
{
struct SplayNode
{
SplayNode *c[2],*f;
int value,size,sum,maxsum,mls,mrs;
bool rev,same;
}*root,*null,*lb,*rb,SS[MAXN];
int SC;
SplayNode * NewNode(int value,SplayNode *f)
{
SplayNode *e=SS+ ++SC;
e->value=value;
e->size=1;e->f=f;
e->sum=e->maxsum=e->mls=e->mrs=value;
e->same=e->rev=false;
e->c[0]=e->c[1]=null;
return e;
}
inline int max(int a,int b){return a>b?a:b;}
void update(SplayNode *p)
{
if (p==null) return;
p->size = p->c[0]->size + p->c[1]->size + 1;
p->sum = p->c[0]->sum + p->c[1]->sum + p->value;
p->mls = p->c[0]->mls;
p->mls = max( p->mls , p->c[0]->sum + p->value);
p->mls = max( p->mls , p->c[0]->sum + p->value + p->c[1]->mls );
p->mrs = p->c[1]->mrs;
p->mrs = max( p->mrs , p->c[1]->sum + p->value);
p->mrs = max( p->mrs , p->c[1]->sum + p->value + p->c[0]->mrs );
p->maxsum = p->value;
p->maxsum = max( p->maxsum , p->c[0]->maxsum );
p->maxsum = max( p->maxsum , p->c[1]->maxsum );
p->maxsum = max( p->maxsum , p->c[0]->mrs + p->value );
p->maxsum = max( p->maxsum , p->c[1]->mls + p->value );
p->maxsum = max( p->maxsum , p->c[0]->mrs + p->c[1]->mls + p->value );
}
void pushdown(SplayNode *p)
{
if (p==null) return;
if (p->rev)
{
p->rev=false;
SplayNode *q=p->c[0]; p->c[0]=p->c[1]; p->c[1]=q;
p->c[0]->rev = !p->c[0]->rev;
p->c[1]->rev = !p->c[1]->rev;
int t=p->mls;
p->mls=p->mrs; p->mrs=t;
}
if (p->same)
{
p->same=false;
p->c[0]->same=p->c[1]->same=true;
p->c[0]->value=p->c[1]->value=p->value;
p->sum = p->maxsum = p->mls = p->mrs = p->value * p->size;
if (p->value < 0)
p->maxsum = p->mls = p->mrs = p->value;
}
}
void rotate(SplayNode *x,int o)//Zig o=0 Zag o=1
{
SplayNode *y=x->f;
pushdown(x->c[0]);
pushdown(x->c[1]);
pushdown(y->c[!o]);
y->c[o] = x->c[!o];
y->c[o]->f=y;
x->f = y->f;
if (y->f->c[0]==y)
y->f->c[0]=x;
else
y->f->c[1]=x;
y->f=x;
x->c[!o]=y;
update(y);
update(x);
if (root==y) root=x;
}
void splay(SplayNode *x,SplayNode *y)
{
pushdown(x);
while (x->f!=y)
{
if (x->f->f==y)
{
if (x->f->c[0]==x)
rotate(x,0);
else
rotate(x,1);
}
else if (x->f->f->c[0] == x->f)
{
if (x->f->c[0]==x)
rotate(x->f,0),rotate(x,0);
else
rotate(x,1),rotate(x,0);
}
else
{
if (x->f->c[1]==x)
rotate(x->f,1),rotate(x,1);
else
rotate(x,0),rotate(x,1);
}
}
}
void select(int k,SplayNode *y)
{
SplayNode *x=root;
pushdown(x);
for (;k != x->c[0]->size + 1;)
{
if (k <= x->c[0]->size)
x=x->c[0];
else
{
k-=x->c[0]->size + 1;
x=x->c[1];
}
pushdown(x);
}
splay(x,y);
}
void Insert(int pos,int tot,int *C)
{
SplayNode *z,*t;
z=t=NewNode(C[1],null);
for (int i=2;i<=tot;i++)
z=z->c[1]=NewNode(C[i],z);
select(pos+1,null);
select(pos+2,root);
root->c[1]->c[0] = t;
t->f=root->c[1];
splay(z,null);
}
void Delete(int pos,int tot)
{
select(pos,null);
select(pos+tot+1,root);
root->c[1]->c[0] = null;
splay(root->c[1],null);
}
void MakeSame(int pos,int tot,int value)
{
select(pos,null);
select(pos+tot+1,root);
root->c[1]->c[0]->same=true;
root->c[1]->c[0]->value=value;
splay(root->c[1]->c[0],null);
}
void Reverse(int pos,int tot)
{
select(pos,null);
select(pos+tot+1,root);
root->c[1]->c[0]->rev=!root->c[1]->c[0]->rev;
splay(root->c[1]->c[0],null);
}
int GetSum(int pos,int tot)
{
select(pos,null);
select(pos+tot+1,root);
pushdown(root->c[1]->c[0]);
return root->c[1]->c[0]->sum;
}
int MaxSum()
{
pushdown(root);
update(root);
return root->maxsum;
}
void init()
{
SC=-1;
null=0;
null=NewNode(-INF,0);
null->size=0;
lb=root=NewNode(-INF,null);
rb=root->c[1]=NewNode(-INF,root);
null->sum = lb->sum = rb->sum=0;
update(root);
}
}Splay;
int N,M,C[MAXL],pos,i,j,A;
char Ctrl[20];
int main()
{
freopen("seq2005.in","r",stdin);
freopen("seq2005.out","w",stdout);
Splay.init();
scanf("%d%d",&N,&M);
for (i=1;i<=N;i++)
scanf("%d",&C[i]);
Splay.Insert(0,N,C);
for (i=1;i<=M;i++)
{
scanf("%s",Ctrl);
switch (Ctrl[0])
{
case 'I':
scanf("%d%d",&pos,&N);
for (j=1;j<=N;j++)
scanf("%d",&C[j]);
Splay.Insert(pos,N,C);
break;
case 'D':
scanf("%d%d",&pos,&N);
Splay.Delete(pos,N);
break;
case 'R':
scanf("%d%d",&pos,&N);
Splay.Reverse(pos,N);
break;
case 'G':
scanf("%d%d",&pos,&N);
A=Splay.GetSum(pos,N);
printf("%d\n",A);
break;
case 'M':
if (Ctrl[2]=='K')
{
scanf("%d%d%d",&pos,&N,&C[0]);
Splay.MakeSame(pos,N,C[0]);
}
else
printf("%d\n",Splay.MaxSum());
break;
}
}
return 0;
}
---
3 树状数组
---
struct BIT{
int n;
int tree[maxn];
void init(int n){
this->n=n;
memset(tree,0,sizeof(tree));
}
int lowbit(int x){
return x&(-x);
}
void add(int x,int val){
for (int i=x;i<=n;i+=lowbit(i)) tree[i]+=val;
}
int query(int x){
int ret=0;
for (int i=x;i>0;i-=lowbit(i)) ret+=tree[i];
return ret;
}
//离散 p=lower_bound(b+1,b+n+1,a[i])-b;
//逆序数 x=(i-1)-query(p);add(p,1);
};
---
4 线段树
---
4.1 单点更新
---
const int MAXN=255111;
struct SegmentTree{
int num[MAXN];
struct Tree{
int l;
int r;
int min;
};
Tree tree[MAXN*4];
void push_up(int root){
tree[root].min=min(tree[root<<1].min,tree[root<<1|1].min);
}
void build(int root,int l,int r){
tree[root].l=l;
tree[root].r=r;
if(tree[root].l==tree[root].r){
tree[root].min=num[l];
return;
}
int mid=(l+r)/2;
build(root<<1,l,mid);
build(root<<1|1,mid+1,r);
push_up(root);
}
void update(int root,int pos,int val){
if(tree[root].l==tree[root].r){
tree[root].min=val;
return;
}
int mid=(tree[root].l+tree[root].r)/2;
if(pos<=mid) update(root<<1,pos,val);
else update(root<<1|1,pos,val);
push_up(root);
}
int query(int root,int L,int R){
if(L<=tree[root].l&&R>=tree[root].r) return tree[root].min;
int mid=(tree[root].l+tree[root].r)/2,ret=INF;
if(L<=mid) ret=min(ret,query(root<<1,L,R));
if(R>mid) ret=min(ret,query(root<<1|1,L,R));
return ret;
}
void init(int n,int d){
for (int i=1;i<=n;i++) num[i]=d;
build(1,1,n);
}
};
---
4.2 区间维护
---
const int INF=0x3f3f3f;
const int MAXN=10000;
struct SegTree{
int num[MAXN];
int _min,_max,_sum;
struct Tree{
int l;
int r;
int max;
int min;
int sum;
int add;
int set;
};
Tree tree[MAXN*4];
void push_up(int root){
tree[root].max=max(tree[root<<1].max,tree[root<<1|1].max);
tree[root].min=min(tree[root<<1].min,tree[root<<1|1].min);
tree[root].sum=tree[root<<1].sum+tree[root<<1|1].sum;
}
void push_down(int root){
if (tree[root].set!=-1){
if (tree[root].l!=tree[root].r){
//传递懒惰标记
tree[root<<1].add=tree[root<<1|1].add=0;
tree[root<<1].set=tree[root<<1|1].set=tree[root].set;
//最更新大值
tree[root<<1].max=tree[root<<1|1].max=tree[root].set;
//更新最小值
tree[root<<1].min=tree[root<<1|1].min=tree[root].set;
//更新区间和
tree[root<<1].sum=(tree[root<<1].r-tree[root<<1].l+1)*tree[root].set;
tree[root<<1|1].sum=(tree[root<<1|1].r-tree[root<<1|1].l+1)*tree[root].set;
}
tree[root].set=-1;
}
if (tree[root].add>0){
if (tree[root].l!=tree[root].r){
//传递懒惰标记
tree[root<<1].add+=tree[root].add;
tree[root<<1|1].add+=tree[root].add;
//更新最大值
tree[root<<1].max+=tree[root].add;
tree[root<<1|1].max+=tree[root].add;
//更新最小值
tree[root<<1].min+=tree[root].add;
tree[root<<1|1].min+=tree[root].add;
//更新区间和
tree[root<<1].sum+=(tree[root<<1].r-tree[root<<1].l+1)*tree[root].add;
tree[root<<1|1].sum+=(tree[root<<1|1].r-tree[root<<1|1].l+1)*tree[root].add;
}
tree[root].add=0;
}
}
void build(int root,int l,int r){
tree[root].l=l;
tree[root].r=r;
if(tree[root].l==tree[root].r){
tree[root].max=num[l];
tree[root].min=num[l];
tree[root].sum=num[l];
tree[root].add=0;
tree[root].set=-1;
return;
}
int mid=(l+r)/2;
build(root<<1,l,mid);
build(root<<1|1,mid+1,r);
push_up(root);
}
void update_add(int root,int L,int R,int val){
if(L<=tree[root].l&&R>=tree[root].r){
tree[root].add+=val;
tree[root].max+=val;
tree[root].min+=val;
tree[root].sum+=(tree[root].r-tree[root].l+1)*val;
return;
}
push_down(root);
int mid=(tree[root].l+tree[root].r)/2;
if(L<=mid) update_add(root<<1,L,R,val);
if(R>mid) update_add(root<<1|1,L,R,val);
push_up(root);
}
void update_set(int root,int L,int R,int val){
if(L<=tree[root].l&&R>=tree[root].r){
tree[root].set=val;
tree[root].add=0;
tree[root].max=val;
tree[root].min=val;
tree[root].sum=(tree[root].r-tree[root].l+1)*val;
return;
}
push_down(root);
int mid=(tree[root].l+tree[root].r)/2;
if(L<=mid) update_set(root<<1,L,R,val);
if (R>mid) update_set(root<<1|1,L,R,val);
push_up(root);
}
void query(int root,int L,int R){
if(L<=tree[root].l&&R>=tree[root].r){
_min=min(_min,tree[root].min);
_max=max(_max,tree[root].max);
_sum+=tree[root].sum;
return;
}
push_down(root);
int mid=(tree[root].l+tree[root].r)/2;
if(L<=mid) query(root<<1,L,R);
if(R>mid) query(root<<1|1,L,R);
}
};
---
---
5 并查集
---
int pa[maxn];
void makeset(int n){
for (int i=0;i<=n;i++) pa[i]=i;
}
int findset(int x){
if (x!=pa[x]) pa[x]=findset(pa[x]);
return pa[x];
}
void unionset(int x,int y){
x=findset(x);
y=findset(y);
if (x!=y) pa[x]=y;
}
---
6 RMQ
---
6.1 取最小值
---
int d[maxn][20];
//元素从1编号到n
void RMQ_init(int A[],int n){
for (int i=1;i<=n;i++) d[i][0]=A[i];
for (int j=1;(1<<j)<=n;j++)
for (int i=1;i+(1<<j)-1<=n;i++)
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++;
return min(d[L][k],d[R-(1<<k)+1][k]);
}
---
6.2 取最小值的下标
---
int d[maxn][20];
//元素从1编号到n
void makeRmqIndex(int A[],int n){
for(int i=1;i<=n;i++) d[i][0]=i;
for(int j=1;(1<<j)<=n;j++)
for(int i=1;i+(1<<j)-1<=n;i++)
d[i][j] = A[d[i][j-1]] < A[d[i+(1<<(j-1))][j-1]]? d[i][j-1]:d[i+(1<<(j-1))][j-1];
}
int rmqIndex(int L,int R,int A[])
{
int k=0;
while ((1<<(k+1))<=R-L+1) k++;
return A[d[L][k]]<A[d[R-(1<<k)+1][k]]? d[L][k]:d[R-(1<<k)+1][k];
}
---
7 LCA的RMQ解法
---
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int INF=0x3f3f3f;
const int maxn=111111;
const int maxm=111111;
int n,m;
struct EDGENODE{
int to;
int w;
int next;
};
struct SGRAPH{
int head[maxn];
EDGENODE edges[maxm];
int edge;
void init(){
memset(head,-1,sizeof(head));
edge=0;
}
void addedge(int u,int v,int c){
edges[edge].w=c,edges[edge].to=v,edges[edge].next=head[u],head[u]=edge++;
}
//------------
int d[maxn][20];
//元素从1编号到n
void makeRmqIndex(int A[],int n){
for(int i=1;i<=n;i++) d[i][0]=i;
for(int j=1;(1<<j)<=n;j++)
for(int i=1;i+(1<<j)-1<=n;i++)
d[i][j] = A[d[i][j-1]] < A[d[i+(1<<(j-1))][j-1]]? d[i][j-1]:d[i+(1<<(j-1))][j-1];
}
int rmqIndex(int L,int R,int A[])
{
int k=0;
while ((1<<(k+1))<=R-L+1) k++;
return A[d[L][k]]<A[d[R-(1<<k)+1][k]]? d[L][k]:d[R-(1<<k)+1][k];
}
//---------------------
int E[maxn*2],R[maxn],D[maxn*2],mn;
void dfs(int u,int p,int d){
E[++mn]=u;
D[mn]=d;
R[u]=mn;
for (int i=head[u];i!=-1;i=edges[i].next){
int v=edges[i].to;
if (v==p) continue;
dfs(v,u,d+1);
E[++mn]=u;
D[mn]=d;
}
}
void LCA_init(){
mn=0;
memset(R,0,sizeof(R));
dfs(1,-1,1);
makeRmqIndex(D,mn);
getd(1,-1,0);
}
int LCA(int u,int v){
if (R[u]>=R[v]) return E[rmqIndex(R[v],R[u],D)];
else return E[rmqIndex(R[u],R[v],D)];
}
//--------------------
int deep[maxn];
void getd(int u,int p,int w){
deep[u]=w;
for (int i=head[u];i!=-1;i=edges[i].next){
int v=edges[i].to;
if (v==p) continue;
getd(v,u,w+edges[i].w);
}
}
int getDis(int u,int v){
int lca=LCA(u,v);
return deep[u]+deep[v]-deep[lca]*2;
}
int done(int x,int y,int z){
int ans=INF,res=0;
int lca1,lca2;
lca1=LCA(x,y);
res=deep[x]+deep[y]-deep[lca1]*2;
lca2=LCA(lca1,z);
res+=deep[lca1]+deep[z]-deep[lca2]*2;
ans=min(ans,res);
lca1=LCA(x,z);
res=deep[x]+deep[z]-deep[lca1]*2;
lca2=LCA(lca1,y);
res+=deep[lca1]+deep[y]-deep[lca2]*2;
ans=min(ans,res);
lca1=LCA(y,z);
res=deep[y]+deep[z]-deep[lca1]*2;
lca2=LCA(lca1,x);
res+=deep[lca1]+deep[x]-deep[lca2]*2;
ans=min(ans,res);
return ans;
}
}solver;
---
---------------
四、字符串
---
1 字典树Trie
---
const int CHARSET = 26;
const int MAX_N_NODES = int(3e5) + 10;
struct TrieNode
{
TrieNode* next[CHARSET];
int num;//记录是不是一个单词
int value;//记录单词出现的次数
TrieNode(){
memset(next,0,sizeof(next));
value=0;
num=0;
}
void clear(){
memset(next,0,sizeof(next));
value=0;
num=0;
}
}*root;
TrieNode nodePool[MAX_N_NODES],*cur;
TrieNode* newNode(){
TrieNode* t = cur++;
t->clear();
return t;
}
void trieInit() {
cur=nodePool;
root=newNode();
}
//插入:
void insert(char* s){
TrieNode* p=root;
int k=0;
while(s[k]!='\0'){
if(!p->next[s[k]-'a']) p->next[s[k]-'a']=newNode();
p=p->next[s[k]-'a'];
p->num++;
k++;
}
p->value=1;
}
//查找
int find(char* s){
TrieNode* p=root;
int k=0;
while(s[k]!='\0'&&p->next[s[k]-'a']){
p=p->next[s[k]-'a'];
k++;
}
if(s[k]=='\0') return p->num;
return 0;
}
//DP查找
void dpfind(char* s,int pos){
TrieNode* p=root;
int k=0;
while(s[k]!='\0'&&p->next[s[k]-'a']){
p=p->next[s[k]-'a'];
if (p->value==1){
//do something like dp...
//f[pos+k+1]=(f[pos+k+1]+f[pos])%MOD;
}
k++;
}
}
---
f[0]=1;
for (int i=1;i<=l;i++)
if (f[i-1]) find(str+i,i-1);
---
2 扩展KMP
---
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int MM=100005;
int next[MM],extand[MM];
char S[MM],T[MM];
void GetNext(const char *T){
int len=strlen(T),a=0;
next[0]=len;
while(a<len-1 && T[a]==T[a+1]) a++;
next[1]=a;
a=1;
for(int k=2;k<len;k++){
int p=a+next[a]-1,L=next[k-a];
if( (k-1)+L >= p){
int j = (p-k+1)>0 ? (p-k+1) : 0;
while(k+j<len && T[k+j]==T[j]) j++;
next[k]=j;
a=k;
}
else
next[k]=L;
}
}
void GetExtand(const char *S,const char *T){
GetNext(T);
int slen=strlen(S),tlen=strlen(T),a=0;
int MinLen = slen < tlen ? slen : tlen;
while(a<MinLen && S[a]==T[a]) a++;
extand[0]=a;
a=0;
for(int k=1;k<slen;k++){
int p=a+extand[a]-1, L=next[k-a];
if( (k-1)+L >= p){
int j= (p-k+1) > 0 ? (p-k+1) : 0;
while(k+j<slen && j<tlen && S[k+j]==T[j]) j++;
extand[k]=j;
a=k;
}
else
extand[k]=L;
}
}
int main(){
while(scanf("%s%s",S,T)==2){
GetExtand(S,T);
for(int i=0;i<strlen(T);i++)
printf("%d ",next[i]);
puts("");
for(int i=0;i<strlen(S);i++)
printf("%d ",extand[i]);
puts("");
}
return 0;
}
---
3 Aho-Corasick自动机
---
const int CHARSET = 26;
const int MAX_N_NODES = int(3e5) + 10;
struct Aho_Corasick{
struct Node{
Node *next[CHARSET];
Node *fail;
int count;//记录当前前缀是完整单词出现的个数
Node(){
memset(next,0,sizeof(next));
fail = NULL;
count = 0;
}
void clear(){
memset(next,0,sizeof(next));
fail = NULL;
count = 0;
}
};
Node *root;
Node nodePool[MAX_N_NODES], *cur;
Node* newNode(){
Node* t=cur++;
t->clear();
return t;
}
void init(){
cur=nodePool;
root=newNode();
}
void insert(char *str){
Node* p=root;
int i=0,index;
while(str[i]){
index=str[i]-'a';
if(p->next[index]==NULL) p->next[index]=newNode();
p=p->next[index];
i++;
}
p->count++;
}
void build_ac_automation(){
int i;
queue<Node*>Q;
root->fail=NULL;
Q.push(root);
while(!Q.empty()){
Node* temp=Q.front();
Q.pop();
Node* p=NULL;
for(i=0;i<CHARSET;i++){
if(temp->next[i]!=NULL){//寻找当前子树的失败指针
p = temp->fail;
while(p!=NULL){
if(p->next[i]!=NULL){//找到失败指针
temp->next[i]->fail=p->next[i];
break;
}
p=p->fail;
}
if(p==NULL) temp->next[i]->fail=root;//无法获取,当前子树的失败指针为根
Q.push(temp->next[i]);
}
}
}
}
int query(char *str){//询问str中包含n个关键字中多少种即匹配
int i=0,cnt=0,index;
Node* p = root;
while(str[i]){
index=str[i]-'a';
while(p->next[index]==NULL&&p!=root) p=p->fail;//失配
p=p->next[index];
if(p==NULL) p = root;//失配指针为根
Node* temp = p;
while(temp!=root&&temp->count!=-1){//寻找到当前位置为止是否出现关键字
cnt+=temp->count;
temp->count=-1;
temp=temp->fail;
}
i++;
}
return cnt;
}
};
---
---4 后缀数组
---
const int maxn=3e5*2+10;
/******************************************************************
** 后缀数组 Suffix Array
** INIT:solver.call_fun(char* s);
** CALL: solver.lcp(int i,int j); //后缀i与后缀j的最长公共前缀
** SP_USE: solver.LCS(char *s1,char* s2); //最长公共字串
******************************************************************/
struct SuffixArray{
int r[maxn];
int sa[maxn],rank[maxn],height[maxn];
int t[maxn],t2[maxn],c[maxn],n;
int m;//模板长度
void init(char* s){
n=strlen(s);
for (int i=0;i<n;i++) r[i]=int(s[i]);
m=300;
}
int cmp(int *r,int a,int b,int l){
return r[a]==r[b]&&r[a+l]==r[b+l];
}
/**
字符要先转化为正整数
待排序的字符串放在r[]数组中,从r[0]到r[n-1],长度为n,且最大值小于m。
所有的r[i]都大于0,r[n]无意义算法中置0
函数结束后,结果放在sa[]数组中(名次从1..n),从sa[1]到sa[n]。s[0]无意义
**/
void build_sa(){
int i,k,p,*x=t,*y=t2;
r[n++]=0;
for (i=0;i<m;i++) c[i]=0;
for (i=0;i<n;i++) c[x[i]=r[i]]++;
for (i=1;i<m;i++) c[i]+=c[i-1];
for (i=n-1;i>=0;i--) sa[--c[x[i]]]=i;
for (k=1,p=1;k<n;k*=2,m=p){
for (p=0,i=n-k;i<n;i++) y[p++]=i;
for (i=0;i<n;i++) if (sa[i]>=k) y[p++]=sa[i]-k;
for (i=0;i<m;i++) c[i]=0;
for (i=0;i<n;i++) c[x[y[i]]]++;
for (i=1;i<m;i++) c[i]+=c[i-1];
for (i=n-1;i>=0;i--) sa[--c[x[y[i]]]]=y[i];
swap(x,y);
p=1;
x[sa[0]]=0;
for (i=1;i<n;i++) x[sa[i]]=cmp(y,sa[i-1],sa[i],k)?p-1:p++;
}
n--;
}
/**
height[2..n]:height[i]保存的是lcp(sa[i],sa[i-1])
rank[0..n-1]:rank[i]保存的是原串中suffix[i]的名次
**/
void getHeight(){
int i,j,k=0;
for (i=1;i<=n;i++) rank[sa[i]]=i;
for (i=0;i<n;i++){
if (k) k--;
j=sa[rank[i]-1];
while (r[i+k]==r[j+k]) k++;
height[rank[i]]=k;
}
}
int d[maxn][20];
//元素从1编号到n
void RMQ_init(int A[],int n){
for (int i=1;i<=n;i++) d[i][0]=A[i];
for (int j=1;(1<<j)<=n;j++)
for (int i=1;i+j-1<=n;i++)
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++;
return min(d[L][k],d[R-(1<<k)+1][k]);
}
void LCP_init(){
RMQ_init(height,n);
}
int lcp(int i,int j){
if (rank[i]>rank[j]) swap(i,j);
return RMQ(rank[i]+1,rank[j]);
}
void call_fun(char* s){
init(s);//初始化后缀数组
build_sa();//构造后缀数组sa
getHeight();//计算height与rank
LCP_init();//初始化RMQ
}
int LCS(char* s1,char* s2){
int p,ans;
int l=strlen(s1);
p=l;
s1[l]='$';
s1[l+1]='\0';
strcat(s1,s2);
call_fun(s1);
ans=0;
for (int i=2;i<=n;i++)
if ((sa[i-1]<p&&sa[i]>p)||(sa[i-1]>p&&sa[i]<p)) ans=max(ans,height[i]);
return ans;
}
}solver;
---
5 字符串hash
---
H(i)=s[i]+s[i+1]x+...s[n-2]x^(n-2-i)+s[n-1]x^(n-1-i)
Hash(i,L)=s[i]+s[i+1]x+...s[i+L-2]x^(L-2)+s[i+L-1]x^(L-1)
=H[i]-H[i+L]*x^L
对于LCP(i,j),二分答案L,判断Hash(i,L)与Hash(j,L)是否相等。
---
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
using namespace std;
typedef unsigned long long ULL;
const int SIZE = 100003;
const int SEED = 13331;
const int MAX_N = 50000 + 10;
char s[MAX_N];
struct HASH{
ULL H[MAX_N];
ULL XL[MAX_N];
int len;
HASH(){}
void build(char *s){
len=strlen(s);
H[len]=0;
XL[0]=1;
for (int i=len-1;i>=0;i--){
H[i]=H[i+1]*SEED+s[i];
XL[len-i]=XL[len-i-1]*SEED;
}
}
ULL hash(int i,int L){
return H[i]-H[i+L]*XL[L];
}
}hs;
LCP
int lcp(int i,int j){
int l=0,r=min(len-i,len-j);
int res=0;
while (l<=r){
int mid=(l+r)/2;
if (hash(i,mid)==hash(j,mid)){
res=mid;
l=mid+1;
}
else{
r=mid-1;
}
}
return res;
}
---
6 后缀自动机
---
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <vector>
#define sz(x) int(x.size())
using namespace std;
typedef vector<int> VI;
const int maxn = 250000+10;
class SuffixAutomaton{
private:
struct Node{
Node *suf, *go[26];
int val;
Node(){
suf=NULL;
val=0;
memset(go,0,sizeof(go));
}
void clear(){
suf=NULL;
val=0;
memset(go,0,sizeof(go));
}
int calc(){
if (suf==0) return 0;
return val-suf->val;
}
};
Node *root,*last;
Node nodePool[maxn*2],*cur;
Node* newNode(){
Node* res=cur++;
res->clear();
return res;
}
int tot;
void extend(int w){
Node *p=last;
Node *np=newNode();
np->val=p->val+1;
while (p&&!p->go[w]){
p->go[w]=np;
p=p->suf;
}
if (!p){
np->suf=root;
tot+=np->calc();
}
else{
Node *q=p->go[w];
if (p->val+1==q->val){
np->suf=q;
tot+=np->calc();
}
else{
Node *nq=newNode();
memcpy(nq->go,q->go,sizeof(q->go));
tot-=p->calc()+q->calc();
nq->val=p->val+1;
nq->suf=q->suf;
q->suf=nq;
np->suf=nq;
tot+=p->calc()+q->calc()+np->calc()+nq->calc();
while (p&&p->go[w]==q){
p->go[w]=nq;
p=p->suf;
}
}
}
last = np;
}
public:
void init(){
cur=nodePool;
root=newNode();
last=root;
}
VI getSubString(char s[]){
VI v;
tot=0;
int len=strlen(s);
for (int i=0;i<len;i++){
extend(s[i]-'a');
v.push_back(tot);
}
return v;
}
int getLCS(char A[],char B[]){
int res=0,step=0;
int lenA=strlen(A);
int lenB=strlen(B);
for (int i=0;i<lenA;i++) extend(A[i]-'a');
Node *p=root;
for (int i=0;i<lenB;i++){
int x=B[i]-'a';
if (p->go[x]){
step++;
p=p->go[x];
}
else{
while (p&&!p->go[x]) p=p->suf;
if (!p){
p=root;
step=0;
}
else{
step=p->val+1;
p=p->go[x];
}
}
res=max(res,step);
}
return res;
}
}atm;
---------------
五、几何
---
1 点·线
---
int dcmp(double x){
if (fabs(x)<EPS) return 0;
return x>0?1:-1;
}
struct point{
double x,y;
point(){}
point(double _x,double _y):x(_x),y(_y){}
/**运算操作**/
bool operator==(point a)const{
return dcmp(a.x-x)==0&&dcmp(a.y-y)==0;
}
bool operator<(point a)const{
return dcmp(x-a.x)==0?dcmp(y-a.y)<0:dcmp(x-a.x)<0;
}
friend point operator+(point a,point b){
return point(a.x+b.x,a.y+b.y);
}//向量+向量=向量
friend point operator-(point a,point b){
return point(a.x-b.x,a.y-b.y);
}//点-点=向量
friend point operator*(point a,double p){
return point(a.x*p,a.y*p);
}//向量*数=向量
friend point operator/(point a,double p){
return point(a.x/p,a.y/p);
}//向量/数=向量
/**基本信息计算**/
double len(){
return hypot(x,y);
}
double len2(){
return x*x+y*y;
}
double distance(point p){
return hypot(x-p.x,y-p.y);
}
/**向量变换**/
point rotate(double rad){
return point(x*cos(rad)-y*sin(rad),x*sin(rad)+y*cos(rad));
}//绕起点逆时针旋转rad
point rotate(point p,double angle)//绕点p逆时针旋转angle角度
{
point v=(*this)-p;
double c=cos(angle),s=sin(angle);
return point(p.x+v.x*c-v.y*s,p.y+v.x*s+v.y*c);
}
point rotleft(){
return point(-y,x);
}//逆时针转90度
point rotright(){
return point(y,-x);
}//顺时针转90度
point normal(){
double L=len();
return point(-y/L,x/L);
}//单位法线即左转90度长度归一
point trunc(double r){
double l=len();
if (!dcmp(l)) return *this;
r/=l;
return point(x*r,y*r);
}//长度变为r
/**读入与输出**/
void input(){
scanf("%lf%lf",&x,&y);
}
void output(){
printf("%0.2f %0.2f\n",x,y);
}
};
typedef point vect;
double dot(point a,point b){
return a.x*b.x+a.y*b.y;
}
double cross(point a,point b){
return a.x*b.y-a.y*b.x;
}
double area3p(point a,point b,point c){
return cross(b-a,c-a)/2;
}//三角形abc的面积
double angle(vect a,vect b){
return acos(dot(a,b)/a.len()/b.len());
}
point GetLineIntersection(point P,vect v,point Q,vect w){
vect u=P-Q;
double t=cross(w,u)/cross(v,w);
return P+v*t;
}//直线交点
double ConvexPolygonArea(point *p,int n){
double area=0;
for (int i=1;i<n-1;i++) area+=cross(p[i]-p[0],p[i+1]-p[0]);
return area/2;
}//多边形面积
struct line{
point a,b;
line(){}
line(point _a,point _b){a=_a;b=_b;}
line(point p,double angle){
a=p;
if (dcmp(angle-PI/2)==0) b=a+point(0,1);
else b=a+point(1,tan(angle));
}//倾斜角angle
line (double _a,double _b,double _c){
if (dcmp(_a)==0){
a=point(0,-_c/_b);
b=point(1,-_c/_b);
}else if (dcmp(_b)==0){
a=point(-_c/_a,0);
b=point(-_c/_a,1);
}else{
a=point(0,-_c/_b);
b=point(1,(-_c-_a)/_b);
}
}//ax+by+c=0
void adjust(){
if (b<a) swap(a,b);
}//两点校准
/**运算操作**/
bool operator==(line v){
return (a==v.a)&&(b==v.b);
}
/**基本信息计算**/
double length(){
return a.distance(b);
}
double angle(){
double k=atan2(b.y-a.y,b.x-a.x);
if (dcmp(k)<0) k+=PI;
if (dcmp(k-PI)==0) k-=PI;
return k;
}
/**线段相关**/
int relation(point p){
int c=dcmp(cross(p-a,b-a));
if (c<0) return 1;//点在逆时针
if (c>0) return 2;//点在顺时针
return 3;//平行
}
bool pointonseg(point p){
return dcmp(cross(p-a,b-a))==0&&dcmp(cross(p-a,p-b))<=0;
}//点p在线段上?
bool parallel(line v){
return dcmp(cross(b-a,v.b-v.a))==0;
}//与线段v平行?
int segcrossseg(line v){
int d1=dcmp(cross(b-a,v.a-a));
int d2=dcmp(cross(b-a,v.b-a));
int d3=dcmp(cross(v.b-v.a,a-v.a));
int d4=dcmp(cross(v.b-v.a,b-v.a));
if ((d1^d2)==-2&&(d3^d4)==-2)return 2;
return ((d1==0&&dcmp(dot(v.a-a,v.a-b)<=0))||
(d2==0&&dcmp(dot(v.b-a,v.b-b)<=0))||
(d3==0&&dcmp(dot(a-v.a,a-v.b)<=0))||
(d4==0&&dcmp(dot(b-v.a,b-v.b)<=0)));
}//线段相交 0-不相交 1-非规范相交 2-规范相交
/**直线相关**/
int linecrosseg(line v){//直线v
int d1=dcmp(cross(b-a,v.a-a));
int d2=dcmp(cross(b-a,v.b-a));
if ((d1^d2)==-2) return 2;
return (d1==0||d2==0);
}//0-平行 1-重合 2-相交
int linecrossline(line v){
if ((*this).parallel(v)) return v.relation(a)==3;
return 2;
}//0-平行 1-重合 2-相交
point crosspoint(line v){
double a1=cross(v.b-v.a,a-v.a);
double a2=cross(v.b-v.a,b-v.a);
return point((a.x*a2-b.x*a1)/(a2-a1),(a.y*a2-b.y*a1)/(a2-a1));
}//交点
double dispointtoline(point p){
return fabs(cross(p-a,b-a))/length();
}//点到线的距离
double dispointtoseg(point p){
if (dcmp(cross(p-b,a-b))<0||dcmp(cross(p-a,b-a))<0) return min(p.distance(a),p.distance(b));
return dispointtoline(p);
}
/**输入输出**/
void input(){
a.input();
b.input();
}
void output(){
a.output();
b.output();
}
};
---
---------------
六、数学
---
2 数论基础
---
/*==============================================*\
| 最大公约数-辗转相除
\*==============================================*/
int gcd(int a,int b){
if (b==0) return a;
return gcd(b,a%b);
}
/*==============================================*\
| 扩展欧几里得
| ax+by=gcd(a,b)
\*==============================================*/
int extgcd(int a,int b,int& x,int& y){
int d=a;
if (b!=0){
d=extgcd(b,a%b,y,x);
y-=(a/b)*x;
}else{
x=1;y=0;
}
return d;
}
/*==============================================*\
| 素数-埃氏筛法
\*==============================================*/
int prime[maxn];
bool is_prime[maxn+1];
int sieve(int n){
int p=0;
for (int i=0;i<=n;i++) is_prime[i]=true;
is_prime[0]=is_prime[1]=false;
for (int i=2;i<=n;i++){
if (is_prime[i]){
prime[p++]=i;
for (int j=2*i;j<=n;j+=i) is_prime[j]=false;
}
}
return p;
}
/*==============================================*\
| 快速幂
\*==============================================*/
LL modPow(LL x,LL n,LL mod){
if (n==0) return 1;
LL res=modPow(x*x%mod,n/2,mod);
if (n&1) res=res*x%mod;
return res;
}
/*==============================================*\
| 高斯消元-列主元
| 求解Ax=b,A为矩阵 无解/多解时返回空数组
\*==============================================*/
const double eps=1e-8;
typedef vector<double>vec;
typedef vector<vec>mat;
vec gaussJordan(const mat& A,const vec& b){
int n=A.size();
mat B(n,vec(n+1));
for (int i=0;i<n;i++)
for (int j=0;j<n;j++) B[i][j]=A[i][j];
for (int i=0;i<n;i++) B[i][n]=b[i];
for (int i=0;i<n;i++){
int pivot=i;
for (int j=i;j<n;j++){
if (abs(B[j][i])>abs(B[pivot][i])) pivot=j;
}
swap(B[i],B[pivot]);
if (abs(B[i][i]<eps)) return vec();//无解或多解
for (int j=i+1;j<=n;j++) B[i][j]/=B[i][i];
for (int j=0;j<n;j++){
if (i!=j){
for (int k=i+1;k<=n;k++) B[j][k]-=B[j][i]*B[i][k];
}
}
}
vec x(n);
for (int i=0;i<n;i++) x[i]=B[i][n];
return x;
}
/*==============================================*\
| 逆元
| ax≡b(mod m) x=a逆×b
| gcd(a,m)!=1逆元不存在
\*==============================================*/
int modInverse(int a,int m){
int x,y;
extgcd(a,m,x,y);
return (m+x%m)%m;
}
---
2 矩阵快速幂
---
/*==============================================*\
| 矩阵快速幂
\*==============================================*/
const int M=10000;
typedef vector<int>vec;
typedef vector<vec>mat;
mat mul(mat &A,mat &B){
mat C(A.size(),vec(B[0].size()));
for (int i=0;i<(int)A.size();i++){
for (int k=0;k<(int)B.size();k++){
for (int j=0;j<(int)B[0].size();j++){
C[i][j]=(C[i][j]+A[i][k]*B[k][j])%M;
}
}
}
return C;
}
mat pow(mat A,LL n){
mat B(A.size(),vec(A.size()));
for (int i=0;i<(int)A.size();i++){
B[i][i]=1;
}
while (n>0){
if (n&1) B=mul(B,A);
A=mul(A,A);
n>>=1;
}
return B;
}
---------------
七、其他
---
1 哈希Hash
---
1.1 普通hash
#include <iostream>
#include <cstring>
using namespace std;
const int maxn=11111;
const int maxh=10000019;
int head[maxh];
int next[maxh];
long long st[maxn];
void hash_init(){
memset(head,0,sizeof(head));
}
int hash(long long p,int prime=10000019){
int h;
//hash操作
h=p%prime;
return h;
}
bool add_hash(int s){
int h=hash(st[s]);
int u=head[h];
while(u){
//if (memcmp(st[u],st[s],sizeof(st[s]))==0) return 0;
//if (strcmp(st[u],st[s])==0) return 0;
if (st[u]==st[s]) return 0;
u=next[u];
}
next[s]=head[h];
head[h]=s;
return 1;
}
bool search_hash(long long p){
int h=hash(p);
int u=head[h];
while (u){
//if (memcmp(st[u],p,sizeof(st[u]))==0) return 1;
//if (strcmp(st[u],str)==0) return 1;
if (st[u]==p) return 1;
u=next[u];
}
return 0;
}
---
1.2 树hash
---
从某个常数开始,每次乘以 p,和一个元素异或,再除以 q 取余,再乘以 p,和下一个元素异或,除以 q 取余.....
一直进行到最后一个元素为止。最后把所得到的结果乘以 b,再对 q 取余。
---
hash[u]=977872;
for(i=0;i<son[u];i++)
{
for(j=i;j<son[u]&&q[i].hash==q[j].hash;j++)
{
hash[u]*=P;
hash[u]^=q[j].hash;
hash[u]%=mod;
}
j--;
ans[u]*=cal(q[i].ans+j-i,j-i+1);
ans[u]%=mod;
i=j;
}
---
2 各种最长子序列
---
void LXS(int* a,int* f,int n)
{
vector<int>d;
int l,r;
REP(i,n)
{
//l=lower_bound(d.begin(),d.end(),a[i])-d.begin();
r=upper_bound(d.begin(),d.end(),a[i])-d.begin();
if (r==sz(d)) d.push_back(a[i]);
else d[r]=a[i];
f[i]=r+1;
}
}
---------------
---------------
---------------
---------------