常见的数据结构
集合结构--->并查集
线性结构--->数组--->栈,队列,双端队列
树状结构--->二叉树,BST--->AVL树,splay树,Treap,Cartesian Tree,Size Balance Tree
图状结构--->邻接矩,阵邻接表,十字链表,邻接多重表
堆形结构--->二叉堆--->左偏堆,斜堆
数学结构--->哈希表
统计结构--->树状数组,线段树
字符结构--->前缀树,后缀树,后缀数组
快速排序
void ksort(int l, int h, int a[]) {
if (h < l + 2) return;
int e = h, p = l;
while (l < h) {
while (++l < e && a[l] <= a[p]);
while (--h > p && a[h] >= a[p]);
if (l < h) swap(a[l], a[h]);
}
swap(a[h], a[p]);
ksort(p, h, a);
ksort(l, e, a);
}
并查集
/*==================================================*\
| 带权值的并查集 | INIT: makeset(n);
| CALL: findset(x); unin(x, y);
\*==================================================*/
struct lset {
int p[N], rank[N], sz;
void link(int x, int y) {
if (x == y) return;
if (rank[x] > rank[y]) p[y] = x; else p[x] = y;
if (rank[x] == rank[y]) rank[y]++;
}
void makeset(int n) {
sz = n;
for (int i = 0; i < sz; i++) {
p[i] = i;
rank[i] = 0;
}
}
int findset(int x) {
if (x != p[x]) p[x] = findset(p[x]);
return p[x];
}
void unin(int x, int y) { link(findset(x), findset(y)); }
void compress() { for (int i = 0; i < sz; i++) findset(i); }
};
树状数组(区间求和)
/*==================================================*\
| INIT: ar[]置为0;
| CALL: add(i, v): 将i点的值加v; sum(i): 求[1, i]的和;
\*==================================================*/
#define typev int // type of res
typev ar[N]; // index: 1 ~ N
int lowb(int t) { return t & (-t); }
void add(int i, typev v) {
for (; i < N; ar[i] += v, i += lowb(i));
}
typev sum(int i) {
typev s = 0;
for (; i > 0; s += ar[i], i -= lowb(i));
return s;
}
二维树状数组
/*==================================================*\
| 二维树状数组
| INIT: c[][]置为0; Row,Col要赋初值
\*==================================================*/
const int N = 10000;
int c[N][N];
int Row, Col;
inline int Lowbit(const int &x) { // x > 0
return x & (-x);
}
int Sum(int i, int j) {
int tempj, sum = 0;
while (i > 0) {
tempj = j;
while (tempj > 0) {
sum += c[i][tempj];
tempj -= Lowbit(tempj);
}
i -= Lowbit(i);
}
return sum;
}
void Update(int i, int j, int num) {
int tempj;
while (i <= Row) {
tempj = j;
while (tempj <= Col) {
c[i][tempj] += num;
tempj += Lowbit(tempj);
}
i += Lowbit(i);
}
}
RMQ问题(区间最小值)
/*==================================================*\
| RMQ离线算法 O(N*logN)+O(1)
| INIT: val[]置为待查询数组; initrmq(n);
\*==================================================*/
int st[20][N], ln[N], val[N];
void initrmq(int n) {
int i, j, k, sk;
ln[0] = ln[1] = 0;
for (i = 0; i < n; i++) st[0][i] = val[i];
for (i = 1, k = 2; k < n; i++, k <<= 1) {
for (j = 0, sk = (k >> 1); j < n; ++j, ++sk) {
st[i][j] = st[i - 1][j];
if (sk < n && st[i][j] > st[i - 1][sk]) st[i][j] = st[i - 1][sk];
}
for (j = (k >> 1) + 1; j <= k; ++j) ln[j] = ln[k >> 1] + 1;
}
for (j = (k >> 1) + 1; j <= k; ++j) ln[j] = ln[k >> 1] + 1;
}
int query(int x, int y) // min of { val[x] ... val[y] }
{
int bl = ln[y - x + 1];
return min(st[bl][x], st[bl][y - (1 << bl) + 1]);
}
/*==================================================*\
| RMQ(Range Minimum/Maximum Query)-st算法(O(nlogn + Q))
| ReadIn() 初始化数组a[0...n-1];
| InitRMQ()利用st算法( O(nlogn) )进行预处理;
| Query()根据输入的下标查询值(O(Q))
| Hint: 下标范围:0...n-1,如果为1...n须稍做修改; 此处实现的的是求
| 大值, 如果求小值需要把max->min
| Call: ReadIn(n); InitRMQ(n); Query(Q);
\*==================================================*/
const int N = 200001;
int a[N], d[20];
int st[N][20];
int main(void) {
int n, Q;
while (scanf("%d%d", &n, &Q) != EOF) {
ReadIn(n);
InitRMQ(n);
Query(Q);
}
return 0;
}
void ReadIn(const int &n) {
int i;
for (i = 0; i < n; ++i) scanf("%d", &a[i]);
}
inline int max(const int &arg1, const int &arg2) { return arg1 > arg2 ? arg1 : arg2; }
void InitRMQ(const int &n) {
int i, j;
for (d[0] = 1, i = 1; i < 21; ++i) d[i] = 2 * d[i - 1];
for (i = 0; i < n; ++i) st[i][0] = a[i];
int k = int(log(double(n)) / log(2)) + 1;
for (j = 1; j < k; ++j)
for (i = 0; i < n; ++i) {
if (i + d[j - 1] - 1 < n) {
st[i][j] = max(st[i][j - 1], st[i + d[j - 1]][j - 1]);
} else break; // st[i][j] = st[i][j-1];
}
}
void Query(const int &Q) {
int i;
for (i = 0; i < Q; ++i) {
int x, y, k; // x, y均为下标:0...n-1
scanf("%d%d", &x, &y);
k = int(log(double(y - x + 1)) / log(2.0));
printf("%d\n", max(st[x][k], st[y - d[k] + 1][k]));
}
}
线段树 (动态范围最小值)
const int maxn=2005+5;
#define lson l,m,rt<<1 //预定子左树
#define rson m+1,r,rt<<1|1 //预定右子树
int sum[maxn<<2];//表示节点,需要开到最大区间的四倍
void pushup(int rt){
//对于编号为rt的节点,他的左右节点分别为rt<<1和rt<<1|1
sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
//造树
void build(int l,int r,int rt=1){
//建树操作,生成一个区间为l~r的完全二叉树
//如果到底,则线段长度为0,表示一个点,输入该点的值
if (l==r) {
sum[rt]=0;
return;
}
//准备子树
int m=(l+r)>>1;
//对当前节点建立子树
build(lson);
build(rson);
//由底向上求和
pushup(rt);
}
//更新点和包含点的枝
void update(int pos,int val,int l,int r,int rt=1){
//pos为更新的位置 val为增加的值,正则加,负则减
//l r为区间的两个端点值
//触底,为一个点的时候,该节点值更新
if (l==r) {
sum[rt]+=val;
return;
}
int m = ( l + r ) >> 1;
if (pos<=m) //pos在左子树的情况下,对左子树进行递归
update(pos, val, lson);
else //pos在右子树的情况下,对右子树进行递归
update(pos, val, rson);
//更新包含该点的一系列区间的值
pushup(rt);
}
//查询点或区间
int query(int L,int R,int l,int r,int rt=1){
// L~R为被查询子区间 l~r为“当前”树的全区间
if (L<=l&&r<=R) //子区间包含“当前”树全区间
return sum[rt]; //返回该节点包含的值
int m=(l+r)>>1;
int res=0;
if (L<=m) //左端点在左子树内
res+=query(L, R, lson);
if (R>m) //右端点在右子树内
res+=query(L, R, rson);
return res;
}
代码多源于网络,更多模板