竞赛常用模板整理(ACM/ICPC/CCSP)

竞赛常用模板(ACM/ICPC/CCSP/蓝桥杯/传智杯等)

  • 常用算法
    • 0 排序算法
      • 0.1 快速排序
      • 0.2 希尔排序
      • 0.3 选择排序
      • 0.4 归并排序
      • 0.5 堆排序
    • 1 素数合数
      • 1.1 埃拉托斯特尼筛法
      • 1.2 合数分解
      • 1.3 生成连续素数表
    • 2 快速幂
    • 3 大数模拟
      • 3.1 大数加法
      • 3.2 大数阶乘
      • 3.3.1 大数相减(String实现)
      • 3.3.2 大数相减(链表实现)
    • 4 GCD
    • 5 LCM
    • 6 全排列
    • 7 二分搜索
  • 并查集
    • 8 并查集
  • 图论
    • 9 最小生成树
      • 9.1 克鲁斯卡尔算法
      • 9.2 Prim普里姆算法
    • 10 拓扑排序
  • 单源最短路
    • 11 迪杰斯特拉算法
  • SPFA
    • 12 最短路径快速算法(Shortest Path Faster Algorithm)
  • Floyd-Warshall
    • 13 弗洛伊德算法
  • 二分图
    • 14 染色法
    • 15 匈牙利算法
  • 动态规划
    • 16 01背包
    • 17 完全背包
    • 18 多重背包
  • LIS
    • 19 最长上升子序列
  • LCS
    • 20 最长公共子序列
  • 计算几何
    • 22 向量基本用法
    • 22 求多边形面积
    • 23 判断线段相交
    • 24 求三角形外心
    • 25 极角排序
  • 字符串
    • 25 克努特-莫里斯-普拉特操作
    • 26 kmp扩展
  • 字典树
    • 27 字典树
    • 28 AC自动机
  • 线段树
    • 29 线段树
      • 29.1 点更新
    • 29.2 区间更新
  • 其他
    • 30.树状数组
    • 31.中国剩余定理(孙子定理)
  • 相关刷题笔记博客

常用算法

0 排序算法

0.1 快速排序

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);
    return ;
}

0.2 希尔排序

void Shell_sort(int s[],int len){
      int tmp,j;
      for(int step=len/2;step>0;step/=2){//设置步长
          for(int i=step;i<=len;++i){
              tmp=s[i];
              for(j=i-step;j>0&&tmp<s[j];j-=step);
              for(int k=i;k>j+step;k-=step)s[k]=s[k-step];
              s[j+step]=tmp;
          }
     }
}

0.3 选择排序

void Select_sort(int s[],int len){
     int k;
     for(int i=1;i<len;++i){
         k=i;
         for(int j=i+1;j<=len;++j)
             if(s[k]>s[j])k=j;
         if(k!=i)swap(s[i],s[k]);
     }
}

0.4 归并排序

void Merge(int s[],int t[],int low,int mid,int high){
	int i=low,j=mid+1,k=low;
     while(i<=mid&&j<=high){
         if(s[i]<=s[j])t[k++]=s[i++];
         else t[k++]=s[j++];
     }
     while(i<=mid)t[k++]=s[i++];
     while(j<=high)t[k++]=s[j++];
     for(int i=low;i<=high;++i)s[i]=t[i];//将区间[low,high]拷贝到原来数组s对应的位置,表示该区间元素已排好序
 }

0.5 堆排序

void Heap_Adjust(int s[],int cur,int len){
     int tmp=s[cur];//先取出当前元素cur
     for(int j=2*cur;j<=len;j*=2){//向下筛选
         if(j<len&&s[j]<s[j+1])++j;
         if(tmp>=s[j])break;
         s[cur]=s[j];cur=j;//将子节点j值赋给父节点cur(不用进行交换)
     }
     s[cur]=tmp;
 }
void Heap_sort(int s[],int len){
     //1、构建大根堆
     for(int i=len/2;i>0;--i)Heap_Adjust(s,i,len);
     //2.调整堆结构+交换堆顶元素与末尾元素
     for(int i=len;i>1;--i){
         swap(s[i],s[1]);
         Heap_Adjust(s,1,i-1);//将[1,i-1]重新调整为大根堆
   }
 }

测试


#include
using namespace std;
 
template<class T>
class MinHeap {
private:
	T* heapArray;//存放堆数据的数组
	int currentSize;//当前堆中的元素个数
	int maxSize;//堆的大小
	//交换位置x和位置y的元素
	void swap(int x, int y) {
		T pas = heapArray[x];
		heapArray[x] = heapArray[y];
		heapArray[y] = pas;
	}
	//构建堆
	void BuildHeap() {
		cout << "你想加入多少元素?" << endl;
		int size;
		cin >> size;
		currentSize = size;
		cout << "请加入你的元素:" << endl;
		for (int i = 0; i < size; i++) {
			T value;
			cin >> value;
			heapArray[i] = value;
		}
		for (int i = currentSize / 2 - 1 ; i >= 0; i--) {
			SiftDown(i);
		}
	}
public:
	//构造函数,参数n为堆的大小
	MinHeap(const int n) {
		if (n <= 0) {
			currentSize = 0;
			maxSize = 0;
			heapArray = new T;
			return;
		}
		currentSize = 0;
		maxSize = n;
		heapArray = new T[maxSize];
		BuildHeap();
	}
	//虚析构函数
	virtual ~MinHeap() {
		delete[]heapArray;
	}
	//层序遍历打印堆中元素
	void print() {
		for (int i = 0; i < currentSize; i++) {
			cout << heapArray[i] << " ";
		}
	}
	//判断是否为叶结点
	bool isLeaf(int pos)const {
		return (pos >= currentSize / 2) && (pos < currentSize);
	}
	//返回左孩子的位置
	int LeftChild(int pos)const {
		return 2 * pos + 1;
	}
	//返回右孩子的位置
	int RightChild(int pos)const {
		return 2 * pos + 2;
	}
	//返回父结点的位置
	int Parent(int pos)const {
		return (pos - 1) / 2;
	}
	//向堆中插入新元素
	bool Insert(const T& newNode) {
		if (currentSize == maxSize) {
			return false;
		}
		heapArray[currentSize] = newNode;
		SiftUp(currentSize);
		currentSize++;
		return true;
	}
	//从堆顶删除最小值
	T& RemoveMin() {
		if (currentSize == 0) {
			cout << "Can't Delete!";
			exit(1);
		}
		else {
			swap(0, --currentSize);
			if (currentSize > 1) {
				SiftDown(0);
			}
			return heapArray[currentSize];
		}
	}
	//删除给定下标元素,并记录删除的元素
	bool Remove(int pos) {
		if ((pos < 0) || (pos >= currentSize)) {
			return false;
		}
		
		
		heapArray[pos] = heapArray[--currentSize];//用最后的元素替代被删除元素
		if (heapArray[Parent(pos)] > heapArray[pos]) {
			SiftUp(pos);
		}
		else {
			SiftDown(pos);
		}
		return true;
	}
	//从pos开始向上调整
	void SiftUp(int pos) {
		int temppos = pos;
		T temp = heapArray[temppos];
		while ((temppos > 0) && (heapArray[Parent(temppos)] > temp)) {
			heapArray[temppos] = heapArray[Parent(temppos)];
			temppos = Parent(temppos);
		}
		heapArray[temppos] = temp;
	}
	//从pos开始向下筛选
	void SiftDown(int pos) {
		int i = pos;
		int j = LeftChild(i);
		T temp = heapArray[i];
		while (j < currentSize) {
			if ((j < currentSize - 1) && (heapArray[j] > heapArray[j + 1])) {
				j++;
			}
			if (temp > heapArray[j]) {
				heapArray[i] = heapArray[j];
				i = j;
				j = LeftChild(j);
			}
			else {
				break;
			}
		}
		heapArray[i] = temp;
	}
};
 
int main() {
	//MinHeap test(100);
	MinHeap<int> test(INT_MAX / 8);
	test.print();
	test.Remove(2);//删除下标为几的数 
	cout<<""<<endl;
	test.RemoveMin();
	test.print();
	
}

1 素数合数

1.1 埃拉托斯特尼筛法

/*
    |埃式筛法|
    |快速筛选素数|
*/
 
int prime[maxn];  
bool is_prime[maxn];
 
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){   //  注意数组大小是n
        if(is_prime[i]){
            prime[p++] = i;
            for(int j = i + i; j <= n; j += i)  //  轻剪枝,j必定是i的倍数
                is_prime[j] = false;
        }
    }
    return p;   //  返回素数个数
}

1.2 合数分解

/*
 *  合数的分解需要先进行素数的筛选
 *  factor[i][0]存放分解的素数
 *  factor[i][1]存放对应素数出现的次数
 *  fatCnt存放合数分解出的素数个数(相同的素数只算一次)
 */

const int MAXN = 10000;

int prime[MAXN + 1];

//  获取素数
void getPrime()
{
    memset(prime, 0, sizeof(prime));
    for (int i = 2; i <= MAXN; i++)
    {
        if (!prime[i])
        {
            prime[++prime[0]] = i;
        }
        for (int j = 1; j <= prime[0] && prime[j] <= MAXN / i; j++)
        {
            prime[prime[j] * i] = 1;
            if (i % prime[j] == 0)
            {
                break;
            }
        }
    }
    return ;
}

long long factor[100][2];
int fatCnt;

//  合数分解
int getFactors(long long x)
{
    fatCnt = 0;
    long long tmp = x;
    for (int i = 1; prime[i] <= tmp / prime[i]; i++)
    {
        factor[fatCnt][1] = 0;
        if (tmp % prime[i] == 0)
        {
            factor[fatCnt][0] = prime[i];
            while (tmp % prime[i] == 0)
            {
                factor[fatCnt][1]++;
                tmp /= prime[i];
            }
            fatCnt++;
        }
    }
    if (tmp != 1)
    {
        factor[fatCnt][0] = tmp;
        factor[fatCnt++][1] = 1;
    }
    return fatCnt;
}

1.3 生成连续素数表

/*
 *  素数筛选,查找出小于等于MAXN的素数
 *  prime[0]存素数的个数
 */

const int MAXN = 100000;
int prime[MAXN + 1];

void getPrime()
{
    memset(prime, 0, sizeof(prime));
    for (int i = 2; i <= MAXN; i++)
    {
        if (!prime[i])
        {
            prime[++prime[0]] = i;
        }
        for (int j = 1; j <= prime[0] && prime[j] <= MAXN / i; j++)
        {
            prime[prime[j] * i] = 1;
            if (i % prime[j] == 0)
            {
                break;
            }
        }
    }
}

2 快速幂

typedef long long LL;   //  视数据大小的情况而定
 
LL powerMod(LL x, LL n, LL m)
{
    LL res = 1;
    while (n > 0){
        if  (n & 1) //  判断是否为奇数,若是则true
            res = (res * x) % m;
        x = (x * x) % m;
        n >>= 1;    //  相当于n /= 2;
    }
    return res;
}

3 大数模拟

3.1 大数加法

string add1(string s1, string s2)
{
    if (s1 == "" && s2 == "")   return "0";
    if (s1 == "")   return s2;
    if (s2 == "")   return s1;
    string maxx = s1, minn = s2;
    if (s1.length() < s2.length()){
        maxx = s2;
        minn = s1;
    }
    int a = maxx.length() - 1, b = minn.length() - 1;
    for (int i = b; i >= 0; --i){
        maxx[a--] += minn[i] - '0'; //  a一直在减 , 额外还要减个'0'
    }
    for (int i = maxx.length()-1; i > 0;--i){
        if (maxx[i] > '9'){
            maxx[i] -= 10;//注意这个是减10
            maxx[i - 1]++;
        }
    }
    if (maxx[0] > '9'){
        maxx[0] -= 10;
        maxx = '1' + maxx;
    }
    return maxx;
}

3.2 大数阶乘

#include 
#include 
 
using namespace std;
 
typedef long long LL;
 
const int maxn = 100010;
 
int num[maxn], len;
 
/*
    在mult函数中,形参部分:len每次调用函数都会发生改变,n表示每次要乘以的数,最终返回的是结果的长度
    tip: 阶乘都是先求之前的(n-1)!来求n!
    初始化Init函数很重要,不要落下
*/
 
void Init() {
    len = 1;
    num[0] = 1;
}
 
int mult(int num[], int len, int n) {
    LL tmp = 0;
    for(LL i = 0; i < len; ++i) {
         tmp = tmp + num[i] * n;    //从最低位开始,等号左边的tmp表示当前位,右边的tmp表示进位(之前进的位)
         num[i] = tmp % 10; //  保存在对应的数组位置,即去掉进位后的一位数
         tmp = tmp / 10;    //  取整用于再次循环,与n和下一个位置的乘积相加
    }
    while(tmp) {    //  之后的进位处理
         num[len++] = tmp % 10;
         tmp = tmp / 10;
    }
    return len;
}
 
int main() {
    Init();
    int n;
    n = 1977; // 求的阶乘数
    for(int i = 2; i <= n; ++i) {
        len = mult(num, len, i);
    }
    for(int i = len - 1; i >= 0; --i)
        printf("%d",num[i]);    //  从最高位依次输出,数据比较多采用printf输出
    printf("\n");
    return 0;
}

3.3.1 大数相减(String实现)

#include 
#include 
using namespace std;
const int N=1005;

void Sub(char *p1,char *p2,int *p3)
{
    int i,j,k=0;
    
    int bit=0,t=0; //bit:表示借位,1:表示需要借位,0:表示不需要借位。t:存储中间计算的位相减值
    int len1=strlen(p1);  //被减数的长度
    int len2=strlen(p2); //减数的长度
    
    for(i=len1-1,j=len2-1;i>=0 && j>=0;--i,--j) //此为循环遍历两数,分别对位进行相减操作
    {
        t=(p1[i]-'0')-(p2[j]-'0')-bit;    //计算两个位之间的差值,同时要考虑借位
        
        if(t<0)  //如果t小于0,表示需要借位,bit赋值为1,且最终相减结果需加10作为调整并存储到p3数组中,自己用笔画一下就好理解.
        {
            bit=1;
          //例:123-456,t相减实际值分别为-3(3-6-0(bit)),-4(2-5-1(bit)),-4(1-4-1(bit)),加10调整后为:
           // 7,6,6,由于最高位相减后还bit为1即还需借位,  因此还需调整,转换为第一种情况,即用1000-667=333,且结果为负    
            p3[k++]=t+10;        
        }
        else
        {
            bit=0; //相减为正,则无需调整,直接将t赋给p3对应位。
            p3[k++]=t;
        }
        
    }
    while(i>=0)  //strlen(p1)>strlen(p2) ,result is greater than zero
    {
        t=p1[i]-'0'-bit;
        if(t<0)
        {
            bit=1;
            p3[k++]=t+10;
        }
        else
        {
            bit=0;
            p3[k++]=t;
        }
        i--;
    }
    while(j>=0) //strlen(p1)
    {
        t=10-bit-(p2[j]-'0');        
        p3[k++]=t;
        j--;
    }
    if(bit==1)  //对仍有进位的情况考虑,主要分两种:一种是strlen(p1)
    {
        p3[0]=10-p3[0];
        for(i=1;i<k;++i)
        {
            p3[i]=10-p3[i]-bit;
        }        
    }
    if(bit==1)
        cout<<"-";
    for(i=k-1;i>=0;--i)
        cout<<p3[i];
    cout<<endl;
}
int main()
{
    char c1[N],c2[N];
    int a[N];
    int i,j;
    while(cin>>c1>>c2)
    {
        memset(a,0,sizeof(a));
        Sub(c1,c2,a);
    }
    return 0;
}

3.3.2 大数相减(链表实现)

#include 
using namespace std;
bool flag = 0;
class Node
{
public:
	int data;
	Node *next;
	Node()
	{
		next = NULL;
	}
	Node(int data)
	{
		this->data = data;
	}
	Node(const Node &temp)
	{
		this->data = temp.data;
	}
};
class Link
{
public:
	Node *head;
	int length;
	Link()
	{
		head = new Node();
		length = 0;
	}
	~Link()
	{
		while (head != NULL)
		{
			Node *p = head->next;
			delete head;
			head = p;
		}
	}
	void insert(const Node &cache)
	{
		Node *temp = new Node(cache);
		temp->next = head->next;
		head->next = temp;
		length++;
	}
};

void Creatlist(Link &link)//输入数字
{
	char cache;
	while (true)
	{
		cache = getchar();
		if (cache == '\n')
			break;
		link.insert(Node(cache - '0'));
	}
}
void Sub(Link &link_one, Link &link_two, Link &link_three)
{
	int i, n, m;
	n = link_one.length;
	m = link_two.length;
	Node *p = link_one.head->next, *q = link_two.head->next;
	for (i = 0; i < m; i++)
	{
		int cache;
		int z=p->data;
		int y=q->data;
		cache = (p->data) - (q->data);
		if (cache < 0)
		{
			p->next->data -= 1;
			cache += 10;
		}
		link_three.insert(cache);
		p = p->next;
		q = q->next;
	}
	for (; i<n; i++)
	{
		int cache = p->data;
		if (cache < 0)
		{
			p->next->data--;
			cache += 10;
		}
		if (p->next == NULL && p->data == 0)
			break;
		link_three.insert(cache);
		p = p->next;
	}
}
void Display(const Link &link)//输出
{
	bool zero = 0;
	if (flag)
		printf("-");
	Node *temp = link.head->next;
	while (temp != NULL)
	{
		if (temp->data != 0)
			zero = 1;
		if (zero)
			printf("%d", temp->data);
		temp = temp->next;
	}
	if (!zero)
		printf("0");
}
int main()
{
	Link link_one, link_two, link_three;//建立链表
	printf("大数减法\n");
	printf("please put first number\n");
	Creatlist(link_one);//输入第一个数
	printf("please put second number\n");
	Creatlist(link_two);//输入第二个数
	if ((link_one.length < link_two.length) || (link_one.length == link_two.length && link_one.head->next->data < link_two.head->next->data))
	{
		flag = 1;
		Sub(link_two, link_one, link_three);   //大数加法
	}
	else
	{
		flag = 0;
		Sub(link_one, link_two, link_three);   //大数加法
	}
	Display(link_three);//输出
    system("pause");
	return 0;
}

4 GCD

int gcd(int big, int small)
{
    if (small > big) swap(big, small);
    int temp;
    while (small != 0){ //  辗转相除法
        if (small > big) swap(big, small);
        temp = big % small;
        big = small;
        small = temp;
    }
    return(big);
}

5 LCM

/*
    |辗转相除法|
    |欧几里得算法|
    |求最小公倍数|
*/
 
int gcd(int big, int small)
{
    if (small > big) swap(big, small);
    int temp;
    while (small != 0){ //  辗转相除法
        if (small > big) swap(big, small);
        temp = big % small;
        big = small;
        small = temp;
    }
    return(big);
}

6 全排列

 

void Pern(int list[], int k, int n) {   //  k表示前k个数不动仅移动后面n-k位数
    if (k == n - 1) {
        for (int i = 0; i < n; i++) {
            printf("%d", list[i]);
        }
        printf("\n");
    }else {
        for (int i = k; i < n; i++) {   //  输出的是满足移动条件所有全排列
            swap(list[k], list[i]);
            Pern(list, k + 1, n);
            swap(list[k], list[i]);
        }
    }
}

7 二分搜索

/*
    |二分搜索|
    |要求:先排序|
    |16/11/05ztx, thanks to wangxiaocai|
*/
 
//  left为最开始元素, right是末尾元素的下一个数,x是要找的数
int bsearch(int *A, int left, int right, int x){
    int m;
    while (left < right){
        m = left + (right - left) / 2;
        if (A[m] >= x)  right = m;   else left = m + 1;    
        // 如果要替换为 upper_bound, 改为:if (A[m] <= v) x = m+1; else y = m;     
    }
    return left;
}
 
/*
    最后left == right  
    如果没有找到135577找6,返回7  
    如果找有多少的x,可以用lower_bound查找一遍,upper_bound查找一遍,下标相减  
    C++自带的lower_bound(a,a+n,x)返回数组中最后一个x的下一个数的地址 
    upper_bound(a,a+n,x)返回数组中第一个x的地址
    如果a+n内没有找到x或x的下一个地址,返回a+n的地址  
    lower_bound(a,a+n,x)-upper_bound(a,a+n,x)返回数组中x的个数
*/ 

并查集

8 并查集

/*
    |合并节点操作|
    |16/11/05ztx, thanks to chaixiaojun|
*/
 
int father[maxn];   //  储存i的father父节点  
 
void makeSet() {  
    for (int i = 0; i < maxn; i++)   
        father[i] = i;  
}  
 
int findRoot(int x) {   //  迭代找根节点
    int root = x; // 根节点  
    while (root != father[root]) { // 寻找根节点  
        root = father[root];  
    }  
    while (x != root) {  
        int tmp = father[x];  
        father[x] = root; // 根节点赋值  
        x = tmp;  
    }  
    return root;  
}  
 
void Union(int x, int y) {  //  将x所在的集合和y所在的集合整合起来形成一个集合。  
    int a, b;  
    a = findRoot(x);  
    b = findRoot(y);  
    father[a] = b;  // y连在x的根节点上   或father[b] = a为x连在y的根节点上;  
}  
 
/*
    在findRoot(x)中:
    路径压缩 迭代 最优版
    关键在于在路径上的每个节点都可以直接连接到根上
*/

图论

9 最小生成树

9.1 克鲁斯卡尔算法

/*
    |Kruskal算法|
    |适用于 稀疏图 求最小生成树|
    |16/11/05ztx thanks to wangqiqi|
*/
 
/*
    第一步:点、边、加入vector,把所有边按从小到大排序
    第二步:并查集部分 + 下面的code
*/
 
void Kruskal() {    
    ans = 0;    
    for (int i = 0; i<len; i++) {    
        if (Find(edge[i].a) != Find(edge[i].b)) {    
            Union(edge[i].a, edge[i].b);    
            ans += edge[i].len;    
        }    
    }    
}    

9.2 Prim普里姆算法

/*
    |Prim算法|
    |适用于 稠密图 求最小生成树|
    |堆优化版,时间复杂度:O(elgn)|
*/
 
struct node {  
    int v, len;  
    node(int v = 0, int len = 0) :v(v), len(len) {}  
    bool operator < (const node &a)const {  // 加入队列的元素自动按距离从小到大排序  
        return len> a.len;  
    }  
};
 
vector<node> G[maxn];
int vis[maxn];
int dis[maxn];
 
void init() {  
    for (int i = 0; i<maxn; i++) {  
        G[i].clear();  
        dis[i] = INF;  
        vis[i] = false;  
    }  
}  
int Prim(int s) {  
    priority_queue<node>Q; // 定义优先队列  
    int ans = 0;  
    Q.push(node(s,0));  // 起点加入队列  
    while (!Q.empty()) {   
        node now = Q.top(); Q.pop();  // 取出距离最小的点  
        int v = now.v;  
        if (vis[v]) continue;  // 同一个节点,可能会推入2次或2次以上队列,这样第一个被标记后,剩下的需要直接跳过。  
        vis[v] = true;  // 标记一下  
        ans += now.len;  
        for (int i = 0; i<G[v].size(); i++) {  // 开始更新  
            int v2 = G[v][i].v;  
            int len = G[v][i].len;  
            if (!vis[v2] && dis[v2] > len) {   
                dis[v2] = len;  
                Q.push(node(v2, dis[v2]));  // 更新的点加入队列并排序  
            }  
        }  
    }  
    return ans; 
}  

10 拓扑排序

/*
 *  拓扑排序
 *  INIT:edge[][]置为图的邻接矩阵;cnt[0...i...n-1]:顶点i的入度。
 */
const int MAXV = 1010;

int edge[MAXV][MAXV];
int cnt[MAXV];

void TopoOrder(int n)
{
    int i, top = -1;
    for (i = 0; i < n; ++i)
    {
        if (cnt[i] == 0)
        {   //  下标模拟堆栈
            cnt[i] = top;
            top = i;
        }
    }
    for (i = 0; i < n; i++)
    {
        if (top == -1)
        {
            printf("存在回路\n");
            return ;
        }
        else
        {
            int j = top;
            top = cnt[top];
            printf("%d", j);
            for (int k = 0; k < n; k++)
            {
                if (edge[j][k] && (--cnt[k]) == 0)
                {
                    cnt[k] = top;
                    top = k;
                }
            }
        }
    }
}

单源最短路

11 迪杰斯特拉算法

  /*
        |Dijkstra算法|
        |适用于边权为正的有向图或者无向图|
        |求从单个源点出发,到所有节点的最短路|
        |优化版:时间复杂度 O(elbn)|
    */
     
    struct node {  
        int v, len;  
        node(int v = 0, int len = 0) :v(v), len(len) {}  
        bool operator < (const node &a)const {  //  距离从小到大排序  
            return len > a.len;  
        }  
    };  
     
    vector<node>G[maxn];  
    bool vis[maxn];  
    int dis[maxn];
     
    void init() {  
        for (int i = 0; i<maxn; i++) {  
            G[i].clear();  
            vis[i] = false;  
            dis[i] = INF;  
        }  
    }  
    int dijkstra(int s, int e) {  
        priority_queue<node>Q;  
        Q.push(node(s, 0)); //  加入队列并排序  
        dis[s] = 0;  
        while (!Q.empty()) {  
            node now = Q.top();     //  取出当前最小的  
            Q.pop();  
            int v = now.v;  
            if (vis[v]) continue;   //  如果标记过了, 直接continue  
            vis[v] = true;  
            for (int i = 0; i<G[v].size(); i++) {   //  更新  
                int v2 = G[v][i].v;  
                int len = G[v][i].len;  
                if (!vis[v2] && dis[v2] > dis[v] + len) {  
                    dis[v2] = dis[v] + len;  
                    Q.push(node(v2, dis[v2]));  
                }  
            }  
        }  
        return dis[e];  
    }  

SPFA

12 最短路径快速算法(Shortest Path Faster Algorithm)

/*
    |SPFA算法|
    |队列优化|
    |可处理负环|
*/
 
vector<node> G[maxn];
bool inqueue[maxn];
int dist[maxn];
 
void Init()  
{  
    for(int i = 0 ; i < maxn ; ++i){  
        G[i].clear();  
        dist[i] = INF;  
    }  
}  
int SPFA(int s,int e)  
{  
    int v1,v2,weight;  
    queue<int> Q;  
    memset(inqueue,false,sizeof(inqueue)); // 标记是否在队列中  
    memset(cnt,0,sizeof(cnt)); // 加入队列的次数  
    dist[s] = 0;  
    Q.push(s); // 起点加入队列  
    inqueue[s] = true; // 标记  
    while(!Q.empty()){  
        v1 = Q.front();  
        Q.pop();  
        inqueue[v1] = false; // 取消标记  
        for(int i = 0 ; i < G[v1].size() ; ++i){ // 搜索v1的链表  
            v2 = G[v1][i].vex;  
            weight = G[v1][i].weight;  
            if(dist[v2] > dist[v1] + weight){ // 松弛操作  
                dist[v2] = dist[v1] + weight;  
                if(inqueue[v2] == false){  // 再次加入队列  
                    inqueue[v2] = true;  
                    //cnt[v2]++;  // 判负环  
                    //if(cnt[v2] > n) return -1;  
                    Q.push(v2);  
                } } }  
    }  
    return dist[e];  
}
 
/*
    不断的将s的邻接点加入队列,取出不断的进行松弛操作,直到队列为空  
    如果一个结点被加入队列超过n-1次,那么显然图中有负环  
*/

Floyd-Warshall

13 弗洛伊德算法

/*
    |Floyd算法|
    |任意点对最短路算法|
    |求图中任意两点的最短距离的算法|
*/
 
for (int i = 0; i < n; i++) {   //  初始化为0  
    for (int j = 0; j < n; j++)  
        scanf("%lf", &dis[i][j]);  
}  
for (int k = 0; k < n; k++) {  
    for (int i = 0; i < n; i++) {  
        for (int j = 0; j < n; j++) {  
            dis[i][j] = min(dis[i][j], dis[i][k] + dis[k][j]);  
        }  
    }
}

二分图

14 染色法

/*
    |交叉染色法判断二分图|
*/
 
int bipartite(int s) {  
    int u, v;  
    queue<int>Q;  
    color[s] = 1;  
    Q.push(s);  
    while (!Q.empty()) {  
        u = Q.front();  
        Q.pop();  
        for (int i = 0; i < G[u].size(); i++) {  
            v = G[u][i];  
            if (color[v] == 0) {  
                color[v] = -color[u];  
                Q.push(v);  
            }  
            else if (color[v] == color[u])  
                return 0;  
        }  
    }  
    return 1;  
}  

15 匈牙利算法

   /*
        |求解最大匹配问题|
        |递归实现|
    */
     
    vector<int>G[maxn];  
    bool inpath[maxn];  //  标记  
    int match[maxn];    //  记录匹配对象  
    void init()  
    {  
        memset(match, -1, sizeof(match));  
        for (int i = 0; i < maxn; ++i) {  
            G[i].clear();  
        }  
    }  
    bool findpath(int k) {  
        for (int i = 0; i < G[k].size(); ++i) {  
            int v = G[k][i];  
            if (!inpath[v]) {  
                inpath[v] = true;  
                if (match[v] == -1 || findpath(match[v])) { // 递归  
                    match[v] = k; // 即匹配对象是“k妹子”的  
                    return true;  
                }  
            }  
        }  
        return false;  
    }  
     
    void hungary() {  
        int cnt = 0;  
        for (int i = 1; i <= m; i++) {  // m为需要匹配的“妹子”数  
            memset(inpath, false, sizeof(inpath)); // 每次都要初始化  
            if (findpath(i)) cnt++;  
        }  
        cout << cnt << endl;  
    }  

    /*
        |求解最大匹配问题|
        |dfs实现|
    */
     
    int v1, v2;  
    bool Map[501][501];  
    bool visit[501];  
    int link[501];  
    int result;  
     
    bool dfs(int x)  {  
        for (int y = 1; y <= v2; ++y)  {  
            if (Map[x][y] && !visit[y])  {  
                visit[y] = true;  
                if (link[y] == 0 || dfs(link[y]))  {  
                    link[y] = x;  
                    return true;  
                } } }  
        return false;  
    }  
     
     
    void Search()  {  
        for (int x = 1; x <= v1; x++)  {  
            memset(visit,false,sizeof(visit));  
            if (dfs(x))  
                result++;  
        }
    }

动态规划

16 01背包

void bag01(int cost,int weight)  {  
    for(i = v; i >= cost; --i)  
    dp[i] = max(dp[i], dp[i-cost]+weight);  
} 

17 完全背包

void complete(int cost, int weight)  {  
    for(i = cost ; i <= v; ++i)  
    dp[i] = max(dp[i], dp[i - cost] + weight);  
}  

18 多重背包

 
void multiply(int cost, int weight, int amount)  {  
    if(cost * amount >= v)  
        complete(cost, weight);  
    else{  
        k = 1;  
        while (k < amount){  
            bag01(k * cost, k * weight);  
            amount -= k;  
            k += k;  
        }  
        bag01(cost * amount, weight * amount);  
    }  
}  
 
// other
 
int dp[1000000];
int c[55], m[110];
int sum;
 
void CompletePack(int c) {
    for (int v = c; v <= sum / 2; ++v){
        dp[v] = max(dp[v], dp[v - c] + c);
    }
}
 
void ZeroOnePack(int c) {
    for (int v = sum / 2; v >= c; --v) {
        dp[v] = max(dp[v], dp[v - c] + c);
    }
}
 
void multiplePack(int c, int m) {
    if (m * c > sum / 2)
        CompletePack(c);
    else{
        int k = 1;
        while (k < m){
            ZeroOnePack(k * c);
            m -= k;
            k <<= 1;
        }
        if (m != 0){
            ZeroOnePack(m * c);
        }
    }
}

LIS

19 最长上升子序列

 
/*
    状态转移dp[i] = max{ 1.dp[j] + 1 };  j
 
void solve(){   // 参考挑战程序设计入门经典;
    for(int i = 0; i < n; ++i){  
        dp[i] = 1;  
        for(int j = 0; j < i; ++j){  
            if(a[j] < a[i]){  
                dp[i] = max(dp[i], dp[j] + 1);  
            } } }
}  
 
/* 
    优化方法:
    dp[i]表示长度为i+1的上升子序列的最末尾元素  
    找到第一个比dp末尾大的来代替 
*/
 
    void solve() {  
        for (int i = 0; i < n; ++i){
            dp[i] = INF;
        }
        for (int i = 0; i < n; ++i) {  
            *lower_bound(dp, dp + n, a[i]) = a[i];  //  返回一个指针  
        }  
        printf("%d\n", *lower_bound(dp, dp + n, INF) - dp;  
    }
 
/*  
    函数lower_bound()返回一个 iterator 它指向在[first,last)标记的有序序列中可以插入value,而不会破坏容器顺序的第一个位置,而这个位置标记了一个不小于value的值。
*/

LCS

20 最长公共子序列

void solve() {  
    for (int i = 0; i < n; ++i) {  
        for (int j = 0; j < m; ++j) {  
            if (s1[i] == s2[j]) {  
                dp[i + 1][j + 1] = dp[i][j] + 1;  
            }else {  
                dp[i + 1][j + 1] = max(dp[i][j + 1], dp[i + 1][j]);  
            } } }
}  

计算几何

22 向量基本用法

struct node {  
    double x; // 横坐标  
    double y; // 纵坐标  
};  
 
typedef node Vector;
 
Vector operator + (Vector A, Vector B) { return Vector(A.x + B.x, A.y + B.y); }  
Vector operator - (Point A, Point B) { return Vector(A.x - B.y, A.y - B.y); }  
Vector operator * (Vector A, double p) { return Vector(A.x*p, A.y*p); }  
Vector operator / (Vector A, double p) { return Vector(A.x / p, A.y*p); }  
 
double Dot(Vector A, Vector B) { return A.x*B.x + A.y*B.y; } // 向量点乘  
double Length(Vector A) { return sqrt(Dot(A, A)); }  // 向量模长  
double Angle(Vector A, Vector B) { return acos(Dot(A, B) / Length(A) / Length(B)); }  // 向量之间夹角  
 
double Cross(Vector A, Vector B) { // 叉积计算 公式  
    return A.x*B.y - A.y*B.x;  
}  
 
Vector Rotate(Vector A, double rad) // 向量旋转 公式  {  
    return Vector(A.x*cos(rad) - A.y*sin(rad), A.x*sin(rad) + A.y*cos(rad));  
}  
 
Point getLineIntersection(Point P, Vector v, Point Q, Vector w) { // 两直线交点t1 t2计算公式   
    Vector u = P - Q;   
    double t = Cross(w, u) / Cross(v, w);  // 求得是横坐标  
    return P + v*t;  // 返回一个点  
}  

22 求多边形面积

node G[maxn];  
int n;  
 
double Cross(node a, node b) { // 叉积计算  
    return a.x*b.y - a.y*b.x;  
}  
 
 
int main()  
{  
    while (scanf("%d", &n) != EOF && n) {  
        for (int i = 0; i < n; i++)   
            scanf("%lf %lf", &G[i].x, &G[i].y);  
        double sum = 0;  
        G[n].x = G[0].x;  
        G[n].y = G[0].y;  
        for (int i = 0; i < n; i++) {   
                sum += Cross(G[i], G[i + 1]);  
        }  
        // 或者  
            //for (int i = 0; i < n; i++) {  
                //sum += fun(G[i], G[(i + 1)% n]);  
            //}  
        sum = sum / 2.0;  
        printf("%.1f\n", sum);  
    }  
    system("pause");  
    return 0;  
}

23 判断线段相交

node P[35][105];     
 
double Cross_Prouct(node A,node B,node C) {     //  计算BA叉乘CA     
    return (B.x-A.x)*(C.y-A.y)-(B.y-A.y)*(C.x-A.x);      
}      
bool Intersect(node A,node B,node C,node D)  {  //  通过叉乘判断线段是否相交;           
    if(min(A.x,B.x)<=max(C.x,D.x)&&         //  快速排斥实验;      
       min(C.x,D.x)<=max(A.x,B.x)&&      
       min(A.y,B.y)<=max(C.y,D.y)&&      
       min(C.y,D.y)<=max(A.y,B.y)&&      
       Cross_Prouct(A,B,C)*Cross_Prouct(A,B,D)<0&&      //  跨立实验;      
       Cross_Prouct(C,D,A)*Cross_Prouct(C,D,B)<0)       //  叉乘异号表示在两侧;      
       return true;      
    else return false;      
}    

24 求三角形外心

Point circumcenter(const Point &a, const Point &b, const Point &c) { //返回三角形的外心        
    Point ret;  
    double a1 = b.x - a.x, b1 = b.y - a.y, c1 = (a1*a1 + b1*b1) / 2;  
    double a2 = c.x - a.x, b2 = c.y - a.y, c2 = (a2*a2 + b2*b2) / 2;  
    double d = a1*b2 - a2*b1;  
    ret.x = a.x + (c1*b2 - c2*b1) / d;  
    ret.y = a.y + (a1*c2 - a2*c1) / d;  
    return ret;  
}  

25 极角排序

double cross(point p1, point p2, point q1, point q2) {  // 叉积计算   
    return (q2.y - q1.y)*(p2.x - p1.x) - (q2.x - q1.x)*(p2.y - p1.y);  
}  
bool cmp(point a, point b)  {  
    point o;  
    o.x = o.y = 0;  
    return cross(o, b, o, a) < 0; // 叉积判断  
}  
sort(convex + 1, convex + cnt, cmp); // 按角排序, 从小到大 

字符串

25 克努特-莫里斯-普拉特操作

   
    void getnext(char str[maxn], int nextt[maxn]) {
        int j = 0, k = -1;
        nextt[0] = -1;
        while (j < m) {
            if (k == -1 || str[j] == str[k]) {
                j++;
                k++;
                nextt[j] = k;
            }
            else
                k = nextt[k];
        }
    }
     
    void kmp(int a[maxn], int b[maxn]) {    
        int nextt[maxm];    
        int i = 0, j = 0;    
        getnext(b, nextt);    
        while (i < n) {    
            if (j == -1 || a[i] == b[j]) { // 母串不动,子串移动    
                j++;    
                i++;    
            }    
            else {    
                // i不需要回溯了    
                // i = i - j + 1;    
                j = nextt[j];    
            }    
            if (j == m) {    
                printf("%d\n", i - m + 1); // 母串的位置减去子串的长度+1    
                return;    
            }    
        }    
        printf("-1\n");
    }    

26 kmp扩展

  #include    
    #include    
     
    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;    
        }    
    }    
    void show(const int *s,int len){    
        for(int i = 0; i < len; i ++)    
                cout << s[i] << ' ';    
        cout << endl;    
    }    
     
    int main() {    
        while(cin >> S >> T) {    
            GetExtand(S,T);    
            show(next,strlen(T));    
            show(extand,strlen(S));    
        }    
        return 0;    
    }   

字典树

27 字典树

   struct Trie{  
        int cnt;  
        Trie *next[maxn];  
        Trie(){  
            cnt = 0;  
            memset(next,0,sizeof(next));  
        }  
    };  
     
    Trie *root;  
     
    void Insert(char *word)  {  
        Trie *tem = root;  
        while(*word != '\0')  {  
            int x = *word - 'a';  
            if(tem->next[x] == NULL)  
                tem->next[x] = new Trie;  
            tem = tem->next[x];  
            tem->cnt++;  
            word++;  
        }  
    }  
     
    int Search(char *word)  {  
        Trie *tem = root;  
        for(int i=0;word[i]!='\0';i++)  {  
            int x = word[i]-'a';  
            if(tem->next[x] == NULL)  
                return 0;  
            tem = tem->next[x];  
        }  
        return tem->cnt;  
    }  
     
    void Delete(char *word,int t) {  
        Trie *tem = root;  
        for(int i=0;word[i]!='\0';i++)  {  
            int x = word[i]-'a';  
            tem = tem->next[x];  
            (tem->cnt)-=t;  
        }  
        for(int i=0;i<maxn;i++)  
            tem->next[i] = NULL;  
    }  
     
    int main() {  
        int n;  
        char str1[50];  
        char str2[50];  
        while(scanf("%d",&n)!=EOF)  {  
            root = new Trie;  
            while(n--)  {  
                scanf("%s %s",str1,str2);  
                if(str1[0]=='i') {
                    Insert(str2); 
                }else if(str1[0] == 's')  {  
                    if(Search(str2))  
                        printf("Yes\n");  
                    else  
                        printf("No\n");  
                }else  {  
                    int t = Search(str2);  
                    if(t)  
                        Delete(str2,t);  
                } } }  
        return 0;  
    }  

28 AC自动机

    #include  
    #include  
    #include  
    #include  
     
    using namespace std;  
     
    #define N 1000010  
     
    char str[N], keyword[N];  
    int head, tail;  
     
    struct node {  
        node *fail;  
        node *next[26];  
        int count;  
        node() { //init  
            fail = NULL;// 默认为空  
            count = 0;  
            for(int i = 0; i < 26; ++i)  
                next[i] = NULL;  
        }  
    }*q[N];  
     
    node *root;  
     
    void insert(char *str)  { // 建立Trie  
        int temp, len;  
        node *p = root;  
        len = strlen(str);  
        for(int i = 0; i < len; ++i)  {  
            temp = str[i] - 'a';  
            if(p->next[temp] == NULL)  
                p->next[temp] = new node();  
            p = p->next[temp];  
        }  
        p->count++;  
    }  
     
    void build_ac() { // 初始化fail指针,BFS 数组模拟队列:   
        q[tail++] = root;  
        while(head != tail)  {  
            node *p = q[head++]; // 弹出队头  
            node *temp = NULL;  
            for(int i = 0; i < 26; ++i)  {  
                if(p->next[i] != NULL)  {  
                    if(p == root) { // 第一个元素fail必指向根  
                        p->next[i]->fail = root;
                    }else {  
                        temp = p->fail; // 失败指针  
                        while(temp != NULL) { // 2种情况结束:匹配为空or找到匹配 
                            if(temp->next[i] != NULL) { // 找到匹配  
                                p->next[i]->fail = temp->next[i];  
                                break;  
                            }  
                            temp = temp->fail;  
                        }  
                        if(temp == NULL) // 为空则从头匹配  
                            p->next[i]->fail = root;  
                    }  
                    q[tail++] = p->next[i]; // 入队  
                } } }  
    }  
     
    int query() // 扫描  
    {  
        int index, len, result;  
        node *p = root; // Tire入口  
        result = 0;  
        len = strlen(str);  
        for(int i = 0; i < len; ++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; // p不动,temp计算后缀串  
            while(temp != root && temp->count != -1)   {  
                result += temp->count;  
                temp->count = -1;  
                temp = temp->fail;  
            }  
        }  
        return result;  
    }  
     
    int main() {  
        int num;  
        head= tail = 0;  
        root = new node();  
        scanf("%d", &num);  
        getchar();  
        for(int i = 0; i < num; ++i) {  
           scanf("%s",keyword);  
            insert(keyword);  
        }  
        build_ac();  
        scanf("%s", str);  
        if(query())  
            printf("YES\n");  
        else  
            printf("NO\n");  
        return 0;  
    }  
     
    /*
        假设有N个模式串,平均长度为L;文章长度为M。 
        建立Trie树:O(N*L) 建立fail指针:O(N*L) 模式匹配:O(M*L) 所以,总时间复杂度为:O( (N+M)*L )。
    */

线段树

29 线段树

29.1 点更新

    struct node
    {
        int left, right;
        int max, sum;
    };
     
    node tree[maxn << 2];
    int a[maxn];
    int n;
    int k = 1;
    int p, q;
    string str;
     
    void build(int m, int l, int r)//m 是 树的标号
    {
        tree[m].left = l;
        tree[m].right = r;
        if (l == r){
            tree[m].max = a[l];
            tree[m].sum = a[l];
            return;
        }
        int mid = (l + r) >> 1;
        build(m << 1, l, mid);
        build(m << 1 | 1, mid + 1, r);
        tree[m].max = max(tree[m << 1].max, tree[m << 1 | 1].max);
        tree[m].sum = tree[m << 1].sum + tree[m << 1 | 1].sum;
    }
     
    void update(int m, int a, int val)//a 是 节点位置, val 是 更新的值(加减的值)
    {
        if (tree[m].left == a && tree[m].right == a){
            tree[m].max += val;
            tree[m].sum += val;
            return;
        }
        int mid = (tree[m].left + tree[m].right) >> 1;
        if (a <= mid){
            update(m << 1, a, val);
        }
        else{
            update(m << 1 | 1, a, val);
        }
        tree[m].max = max(tree[m << 1].max, tree[m << 1 | 1].max);
        tree[m].sum = tree[m << 1].sum + tree[m << 1 | 1].sum;
    }
     
    int querySum(int m, int l, int r)
    {
        if (l == tree[m].left && r == tree[m].right){
            return tree[m].sum;
        }
        int mid = (tree[m].left + tree[m].right) >> 1;
        if (r <= mid){
            return querySum(m << 1, l, r);
        }
        else if (l > mid){
            return querySum(m << 1 | 1, l, r);
        }
        return querySum(m << 1, l, mid) + querySum(m << 1 | 1, mid + 1, r);
    }
     
    int queryMax(int m, int l, int r)
    {
        if (l == tree[m].left && r == tree[m].right){
            return tree[m].max;
        }
        int mid = (tree[m].left + tree[m].right) >> 1;
        if (r <= mid){
            return queryMax(m << 1, l, r);
        }
        else if (l > mid){
            return queryMax(m << 1 | 1, l, r);
        }
        return max(queryMax(m << 1, l, mid), queryMax(m << 1 | 1, mid + 1, r));
    } 
     
    build(1,1,n);  
    update(1,a,b);  
    query(1,a,b);

29.2 区间更新

   typedef long long ll;  
    const int maxn = 100010;  
     
    int t,n,q;  
    ll anssum;  
     
    struct node{  
        ll l,r;  
        ll addv,sum;  
    }tree[maxn<<2];  
     
    void maintain(int id) {  
        if(tree[id].l >= tree[id].r)  
            return ;  
        tree[id].sum = tree[id<<1].sum + tree[id<<1|1].sum;  
    }  
     
    void pushdown(int id) {  
        if(tree[id].l >= tree[id].r)  
            return ;  
        if(tree[id].addv){  
            int tmp = tree[id].addv;  
            tree[id<<1].addv += tmp;  
            tree[id<<1|1].addv += tmp;  
            tree[id<<1].sum += (tree[id<<1].r - tree[id<<1].l + 1)*tmp;  
            tree[id<<1|1].sum += (tree[id<<1|1].r - tree[id<<1|1].l + 1)*tmp;  
            tree[id].addv = 0;  
        }  
    }  
     
    void build(int id,ll l,ll r) {  
        tree[id].l = l;  
        tree[id].r = r;  
        tree[id].addv = 0;  
        tree[id].sum = 0;  
        if(l==r)  {  
            tree[id].sum = 0;  
            return ;  
        }  
        ll mid = (l+r)>>1;  
        build(id<<1,l,mid);  
        build(id<<1|1,mid+1,r);  
        maintain(id);  
    }  
     
    void updateAdd(int id,ll l,ll r,ll val) {  
        if(tree[id].l >= l && tree[id].r <= r)  
        {  
            tree[id].addv += val;  
            tree[id].sum += (tree[id].r - tree[id].l+1)*val;  
            return ;  
        }  
        pushdown(id);  
        ll mid = (tree[id].l+tree[id].r)>>1;  
        if(l <= mid)  
            updateAdd(id<<1,l,r,val);  
        if(mid < r)  
            updateAdd(id<<1|1,l,r,val);  
        maintain(id);  
    }  
     
    void query(int id,ll l,ll r) {  
        if(tree[id].l >= l && tree[id].r <= r){  
            anssum += tree[id].sum;  
            return ;  
        }  
        pushdown(id);  
        ll mid = (tree[id].l + tree[id].r)>>1;  
        if(l <= mid)  
            query(id<<1,l,r);  
        if(mid < r)  
            query(id<<1|1,l,r);  
        maintain(id);  
    }  
     
    int main() {  
        scanf("%d",&t);  
        int kase = 0 ;  
        while(t--){  
            scanf("%d %d",&n,&q);  
            build(1,1,n);  
            int id;  
            ll x,y;  
            ll val;  
            printf("Case %d:\n",++kase);  
            while(q--){  
                scanf("%d",&id);  
                if(id==0){  
                    scanf("%lld %lld %lld",&x,&y,&val);  
                    updateAdd(1,x+1,y+1,val);  
                }  
                else{  
                    scanf("%lld %lld",&x,&y);  
                    anssum = 0;  
                    query(1,x+1,y+1);  
                    printf("%lld\n",anssum);  
                } } }  
        return 0;  
    }  

其他

30.树状数组

   #include
    #include
    #include
    #include
    #include
     
    using namespace std;
     
    typedef long long ll;
     
    const int maxn = 50005;
     
    int a[maxn];
    int n;
     
    int lowbit(const int t) {
        return t & (-t);
    }
     
    void insert(int t, int d) {
        while (t <= n){
            a[t] += d;
            t = t + lowbit(t);
        }
    }
     
    ll getSum(int t) {
        ll sum = 0;
        while (t > 0){
            sum += a[t];
            t = t - lowbit(t);
        }
        return sum;
    }
     
    int main() {
        int t, k, d;
        scanf("%d", &t);
        k= 1;
        while (t--){
            memset(a, 0, sizeof(a));
            scanf("%d", &n);
            for (int i = 1; i <= n; ++i) {
                scanf("%d", &d);
                insert(i, d);
            }
            string str;
            printf("Case %d:\n", k++);
            while (cin >> str) {
                if (str == "End")   break;
                int x, y;
                scanf("%d %d", &x, &y);
                if (str == "Query")
                    printf("%lld\n", getSum(y) - getSum(x - 1));
                else if (str == "Add")
                    insert(x, y);
                else if (str == "Sub")
                    insert(x, -y);
            }
        }
        return 0;
    }

31.中国剩余定理(孙子定理)

    int CRT(int a[],int m[],int n)  {    
        int M = 1;    
        int ans = 0;    
        for(int i=1; i<=n; i++)    
            M *= m[i];    
        for(int i=1; i<=n; i++)  {    
            int x, y;    
            int Mi = M / m[i];    
            extend_Euclid(Mi, m[i], x, y);    
            ans = (ans + Mi * x * a[i]) % M;    
        }    
        if(ans < 0) ans += M;    
        return ans;    
    }  
     
    void extend_Euclid(int a, int b, int &x, int &y)  {  
        if(b == 0) {  
            x = 1;  
            y = 0;  
            return;  
        }  
        extend_Euclid(b, a % b, x, y);  
        int tmp = x;  
        x = y;  
        y = tmp - (a / b) * y;  
    }  

相关刷题笔记博客

竞赛常用模板整理(ACM/ICPC/CCSP)
常见图论优化

Leetcode算法刷题笔记1-链表
Leetcode算法刷题笔记2-栈、队、堆
Leetcode算法刷题笔记3-递归与回溯
Leetcode算法刷题笔记4-贪心
Leetcode算法刷题笔记5-二叉树
Leetcode算法刷题笔记6-图
Leetcode算法刷题笔记7-动态规划
Leetcode算法刷题笔记8-二分查找

你可能感兴趣的:(Leetcode算法刷题笔记,acm竞赛,icpc,算法,c++,leetcode)