模板整理(二)

13.树状数组

#include<cstdio>
#include<cstring>
#define lowerBit(x) (x&(-x))
int num[10000];
int n;
void UpDate(int x,int y)//把第x个数加y
{
	while (x <= n)
	{
		num[x] += y;
		x = x+lowerBit(x);
	}
}
int Query(int x)//求从1到x的和 
{
	int sum = 0;
	while (x > 0)
	{
		sum += num[x];
		x = x-lowerBit(x);//x&(x-1)
	}
	   return sum;
}
int main()
{
	scanf ("%d",&n);
	memset(num,0,sizeof(num));
	for (int i = 1 ; i <= n ; i++)
	{
		int t;
		scanf ("%d",&t);
		UpDate(i,t);
	}
	
	int m;
	scanf ("%d",&m);
	while (m--)
	{
		int x,y;
		scanf ("%d %d",&x,&y);//看不懂
		printf ("%d
",Query(y)-Query(x-1));
	}
	   return 0;
}

  

 

14.线段树//看不懂

 

struct Node//不要左右子节点指针的做法 
{
	int L,R;
	int minV,maxV;
	int Mid()
	{
		return (L+R)/2;//还有这操作
	}
};
Node tree[800010];//4倍叶子节点数量就够 


void BuildTree(int root, int L, int R)
{
	tree[root].L = L;
	tree[root].R = R;
	tree[root].minV = INF;//这是为什么?到底哪个是大的
	
	 
	
	tree[root].maxV = -INF;//那个是小的?
	if(L!=R)
	{
		BuildTree(2*root+1, L, (L+R)/2);
		BuildTree(2*root+2, (L+R)/2+1, R);
	}
}


void Insert(int root, int i, int v)
//将第i个数,其值为v,插入线段树 
{
	if(tree[root].L == tree[root].R)//成立则亦有tree[root].R==i 
	{
		tree[root].minV = tree[root].maxV = v;
		return ;
	}
	
	tree[root].minV = min(tree[root].minV , v);
	tree[root].maxV = max(tree[root].maxV , v);
	if(i <= tree[root].Mid())
	Insert(2*root + 1, i, v);
	else
	Insert(2*root + 2, i, v);
}


void Query(int root, int s, int e)
//查询区间[s,e]中的最大值和最小值,如果更优就记录在全局变量里 
{
	if( tree[root].minV >= minV && tree[root].maxV <= maxV )
		return;
	if( tree[root].L == s && tree[root].R == e )
	{
		minV = min( minV, tree[root].minV );
		//minV = min( minV, tree[root].minV );
		maxV = max( maxV, tree[root].maxV );
		return ;
	}
	if( e <= tree[root].Mid() )
		Query( 2*root + 1, s, e );
	else if( s > tree[root].Mid() )
		Query( 2*root + 2, s, e );
	else
	{
		Query( 2*root + 1, s, tree[root].Mid() );
		Query( 2*root + 2, tree[root].Mid() + 1, e );
		
	}

}

  

15.KMP

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//S: a b a b b a b a b a d a b a b a a a b a b a a
//                                               j
//                      T: a b a b a a a b a b a a
//                  next :-1 0 0 1 2 3 1 1 2 3 4 5
char s[1000], t[1000];
int next[1000] = {-1, 0, 0, 1, 2, 3, 1, 1, 2, 3, 4, 5};
int Kmp(char* s, int n, char* t, int m) {
    int i = 0, j = 0;
    while(i < n) {
        if(j == -1 || s[i] == t[j]) {
            ++i; ++j;
            if(j == m) {
                return i - m + 1;
            }
        }
        else {
            j = next[j];
        }
    }
    return -1;
}


int main()
{
    //ababababadababaaababaa
    //ababaaababaa
    //ababcabcacbab
    //abc
    scanf("%s%s", s, t);
    int l1 = strlen(s);
    int l2 = strlen(t);
    printf("第一个匹配的位置%d
", Kmp(s, l1, t, l2));
    return 0;
}


//next[i]: 0 -> i-1 最大的前缀和后缀匹配的长度 0 -> n-1
//S: a b a b b a b a b a d a b a b a a a b a b a a
//T: a b a b a a a b a b a a
//  -1 0 0 1 2 3 1 1 2 3 4 5
//从头选择next[j]个字符和从尾向前选择next[j]个字符是相等的
//
//1>, S串和T串前面这些字符是相等的
//2>, T串前面字符有next[j]前缀和后缀匹配的长度

  

 

16.二分图

 

这个算法的主要思想还是“递归”,通过递归腾出位置来让更多的人匹配,以达到匹配人数最大化
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int f[500+5];		//女和哪个男配对 
bool fr[505][505];		//可用vector<int> d[505]代替 
bool vis[505];		//标记数组,表示这个人搜索过 
int k,n,m;

bool find(int x)		//寻找x男生,返回:能否找到人去匹配 
{
	for (int i = 1 ; i <= m ; i++)
	{
		if (fr[x][i] && !vis[i])
		{
			vis[i] = true;		//首先标记
			if (f[i] == -1)		//如果该女生没有和别人匹配 
			{
				f[i] = x;		//则和该男生匹配 
				return true;		//表示匹配完成 
			}
			else if (find(f[i]))		//如果该女生匹配的男生可以找到其他的女生匹配
			{
				f[i] = x;//递归的思想
				return true;
			}
		}
	}
	return false;
}

int main()
{
	while (~scanf ("%d",&k) && k)
	{
		scanf ("%d %d",&n,&m);
		memset(f,-1,sizeof(f));		//初始化,表示没有和任何人配对
		memset(fr,false,sizeof(fr));		//初始化 
		for (int i = 1 ; i <= k ; i++)
		{
			int x,y;
			scanf ("%d %d",&x,&y);
			fr[x][y] = true;
		}
		
		int ans = 0;		//表示已经配对的男生数 
		for (int i = 1 ; i <= n ; i++)
		{
			memset(vis,false,sizeof(vis));
			if (find(i))
				ans++;
		}
		printf ("%d
",ans);
	}
	return 0;
}

17.字典树模板

 1 #include<cstdio>
 2 #include<cstring>
 3 #define idx(x) (x-'a')
 4 struct Node
 5 {
 6     int v;
 7     Node *next[26];        //指向某个节点,作为其子节点之一 
 8     void init()
 9     {
10         v = 0;        //当前节点有多少人公用
11         for (int i = 0 ; i < 26 ; i++)
12             next[i] = NULL; 
13     }
14 }Trie[100000];        //事先把内存分配好了 
15 int ant;        //下一个节点要保存到的位置 
16 void insert(char str[])
17 {
18     Node *p = &Trie[0];        //现在执行到的节点 
19     int l = strlen(str);
20     for (int i = 0 ; i < l ; i++)
21     {
22         if (p->next[idx(str[i])] == NULL)
23         {
24             p->next[idx(str[i])] = &Trie[ant];
25             ant++;
26             Trie[ant].init();            //随手初始化下一个节点 
27             Trie[ant-1].v = 1;
28             p = &Trie[ant-1];
29         }
30         else
31         {
32             p->v++;
33             p = p->next[idx(str[i])];
34         }
35     }
36 }
37 
38 int Query(char str[])        //char *str
39 {
40     int length = 0;
41     Node p = Trie[0];
42     int l = strlen(str);
43     for (int i = 0 ; i < l ; i++)
44     {
45         if (p.next[idx(str[i])] == NULL)        //到此节点没有公共前缀的串了
46         {
47             break;
48         }
49         else
50         {
51             length++;
52             p = *p.next[idx(str[i])];
53         }
54     }
55     return length;
56 }
57 
58 int main()
59 {
60     int n,m;
61     char str[20];
62     while (~scanf ("%d %d",&n,&m))
63     {
64         ant = 1;
65         Trie[ant].init();
66         for (int i = 1 ; i <= n ; i++)
67         {
68             scanf ("%s",str);
69             insert(str);        //建树 
70         }
71         for (int i = 1 ; i <= m ; i++)
72         {
73             scanf ("%s",str);        //m次查询,查str的最长公共前缀
74             printf ("%d
",Query(str));
75         }
76     }
77     return 0;
78 }
79 /*
80 3 5
81 abac
82 abcd
83 accc
84 
85 a
86 ab
87 abe
88 bc
89 aca
90 
91 
92 */
永远渴望,大智若愚(stay hungry, stay foolish)
原文地址:https://www.cnblogs.com/h-hkai/p/7410385.html