暑假集训7月23日 树状数组 trie树 AC自动机

本文集展示了多种算法题目的解决思路,包括KMP字符串匹配、树状数组应用、字典树和AC自动机实现,深入解析了后序遍历、逆序对计算、字符串查找等核心算法,提供丰富的代码实例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接:树状数组 trie树 AC自动机

A:
思路:kmp直接进行匹配

#include <iostream>
using namespace std;
char S[1000100];
char T[10100];
int nextval[10100];
int n, m;
void get_next()
{
    int i = 1, j = 0;
    nextval[1] = 0;
    while (i <= m)
    {
        if (j == 0 || T[i] == T[j])
        {
            ++i, ++j;
            nextval[i] = j;
        }
        else j = nextval[j];
    }
}
void kmp()
{
    int i = 1, j = 1, cnt = 0;
    while (i <= n && j <= m)
    {
        if (j == 0 || S[i] == T[j]) i++, j++;
        else j = nextval[j];
        if (j > m)
        {
            cnt++;
            j = nextval[j];
        }
    }
    printf("%d\n", cnt);
}
int main()
{
    int t;
    scanf("%d", &t);
    while (t--)
    {
        scanf("%s", &T[1]);
        scanf("%s", &S[1]);
        n = strlen(S + 1);
        m = strlen(T + 1);
        get_next();
        kmp();
    }
}

B:
思路:后序遍历+树状数组

#include <iostream>
#include <queue>
#include <string>
#include <string.h>
const int maxn = 100010;
using namespace std;
int n;
struct node
{
	int v, next;
}e[maxn<<1];
int head[maxn];
int cnt = 0;
int time = 0;
int c[maxn];
int a[maxn];
bool vis[maxn];
struct point
{
	int stime, etime;
}p[maxn];
void add(int u, int v)
{
	e[++cnt].v = v;
	e[cnt].next = head[u];
	head[u] = cnt;
}
void dfs(int u)
{
	p[u].stime = ++time;
	vis[u] = true;
	for (int i = head[u]; i; i = e[i].next)
	{
		if (vis[e[i].v]) continue;
		dfs(e[i].v);
	}
	p[u].etime = time;
}
int lowbit(int x)
{
	return x & (-x);
}
void update(int x,int k)
{
	while (x <= n)
	{
		c[x] += k;
		x += lowbit(x);
	}
}
int getsum(int x)
{
	int ans = 0;
	while (x >= 1)
	{
		ans += c[x];
		x -= lowbit(x);
	}
	return ans;
}
int main() 
{         
	scanf("%d", &n);
	for (int i = 1; i <= n; i++)
	{
		a[i] = 1;
		update(i, 1);
	}
	for (int i = 1; i < n; i++)
	{
		int u, v;
		scanf("%d%d", &u, &v);
		add(u, v);
		add(v, u);
	}
	dfs(1);
	//for (int i = 1; i <= n; i++) cout << p[i].stime << " " << p[i].etime << endl;
	int m;
	scanf("%d", &m);
	while (m--)
	{
		char op;
		int x;
		scanf(" %c%d", &op, &x);
		if (op == 'Q')
		{
			printf("%d\n", getsum(p[x].etime) - getsum(p[x].stime - 1));
		}
		else
		{
			if (a[x]) {
				a[x] = 0;
				update(p[x].stime, -1);
			}
			else {
				a[x] = 1;
				update(p[x].stime, 1);
			}
		}
	}
}

C:
思路:
有交点→(x2-x1)*(y2-y1)< 0
以x为下标 求y的逆序对即可
暴力求逆序对会T掉,需要用线段树或者树状数组
这里给出树状数组解法

#include <iostream>
#include <queue>
#include <string>
#include <string.h>
const int maxn = 1010;
#define ll long long
using namespace std;
int n, m, k;
queue <int> q;
struct node
{
	int x, y;
}line[maxn*maxn];
bool cmp(node& n1, node& n2)
{
	if(n1.x==n2.x)
		return n1.y < n2.y;
	return n1.x < n2.x;
}
int c[maxn];
int lowbit(int x)
{
	return x & (-x);
}
void update(int x,int k)
{
	while (x <= m)
	{
		c[x] += k;
		x += lowbit(x);
	}
}
int getsum(int x)
{
	int ans = 0;
	while (x >= 1)
	{
		ans += c[x];
		x -= lowbit(x);
	}
	return ans;
}
int main() 
{         
	int t;
	scanf("%d", &t);
	int kase = 0;
	while (t--)
	{
		while (q.size()) q.pop();
		memset(c, 0, sizeof(c));
		scanf("%d%d%d", &n, &m, &k);
		for (int i = 1; i <= k; i++)
		{
			scanf("%d%d", &line[i].x, &line[i].y);
		}
		sort(line + 1, line + 1 + k, cmp);
		ll ans = 0;
		for (int i = 1,j=1; i <= k;i++)
		{
			ans += j - 1 - getsum(line[i].y);
			//cout << ans << endl;
			//cout <<i<<":"<< getsum(line[i].y+1) << endl;
			if (line[i + 1].x > line[i].x)
			{
				j += q.size()+1;
				while (q.size())
				{
					int tmp = q.front();
					update(tmp, 1);
					//cout << "update:" << tmp << endl;
					q.pop();
				}
				update(line[i].y, 1);
				//cout << "update2:" << line[i].y << endl;
			}
			else //如果下一个的x不比这一个大,延缓此次update
				q.push(line[i].y);
		}
		//cout << getsum(4) << endl;
		printf("Test case %d: %lld\n", ++kase, ans);
	}
}

D:
思路:字典树插入与查找

#include <iostream>
#include <queue>
#include <string>
#include <string.h>
const int maxn = 1010;
#define ll long long
using namespace std;
const int maxnode = 1010000;
const int maxchar = 26;
int tried[maxnode][maxchar];
char a[maxnode][maxchar];
int color[maxnode];
char s[25];
int cnt = 0;
void insert(char* s)
{
	int len = strlen(s);
	int p = 0;
	color[p]++;
	for (int i = 0; i < len; i++)
	{
		int c = s[i] - 'a';
		if (!tried[p][c])
		{
			tried[p][c] = ++cnt;
			color[cnt]++;
			p = cnt;
		}
		else
		{
			p = tried[p][c];
			color[p]++;
		}
	}
}
void search(char* s) {
	int len = strlen(s);
	int p = 0;
	for (int i = 0; i < len; i++) {		
		int c = s[i] - 'a';
		p = tried[p][c];
		printf("%c", s[i]);
		if (color[p]==1) return;	
	}
}
int main() 
{         
	int tot = 0;
	while (scanf("%s",a[++tot])!=EOF)
	{
		insert(a[tot]);
	}
	for (int i = 1; i <= tot; i++)
	{
		printf("%s ", a[i]);
		search(a[i]);
		printf("\n");
	}
}

F:
思路:AC自动机模板

#include<iostream>
#include<algorithm>
#include<string.h>
#include <queue>
using namespace std;
const int maxn = 1000001;
char s[maxn];
int n, cnt;
queue <int> q;
struct node
{
    int son[26], flag, fail;
}trie[maxn];
void insert(char* s)
{
    int u = 1, len = strlen(s);
    for (int i = 0; i < len; i++)
    {
        int v = s[i] - 'a';
        if(!trie[u].son[v]) trie[u].son[v] = ++cnt;
        u = trie[u].son[v];
    }
    trie[u].flag++;
}
void getfail()
{
    for (int i = 0; i < 26; i++) trie[0].son[i] = 1;
    q.push(1);
    trie[1].fail = 0;
    while (q.size())
    {
        int u = q.front();
        q.pop();
        for (int i = 0; i < 26; i++)
        {
            int v = trie[u].son[i];
            int Fail = trie[u].fail;
            if (!v) { trie[u].son[i] = trie[Fail].son[i]; continue; }
            trie[v].fail = trie[Fail].son[i];
            q.push(v);
        }
    }
}
int query(char* s)
{
    int u = 1, ans = 0, len = strlen(s);
    for (int i = 0; i < len; i++)
    {
        int v = s[i] - 'a';
        int k = trie[u].son[v];
        while (k > 1 && trie[k].flag != -1)
        {
            ans += trie[k].flag;
            trie[k].flag = -1;
            k = trie[k].fail;
        }
        u = trie[u].son[v];
    }
    return ans;
}
int main() 
{
    int t;
    scanf("%d", &t);
    while (t--)
    {
        cnt = 1;
        memset(trie, 0, sizeof(trie));
        scanf("%d", &n);
        while (n--)
        {
            scanf("%s", &s);
            insert(s);
        }
        getfail();
        scanf("%s", &s);
        printf("%d\n", query(s));
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值