DTOJ#5127 字符串

7 篇文章 0 订阅
2 篇文章 0 订阅

题面

你有两个字符串可重集合 S , T S, T S,T,初始时为空。

你要维护这两个字符串集合,支持加入和删除字符串,查询这两个集合的最大权匹配。

定义集合 S , T S, T S,T 的一组匹配方案为,有若干个二元组 ( s i , t i ) (s_i, t_i) (si,ti),其中 s i ∈ S , t i ∈ T , S , T s_i ∈ S, t_i ∈ T,S, T siS,tiTS,T 中的每个元素最多出现在一个二元组中。

定义集合 S , T S, T S,T 一组匹配方案的权值为,$ \sum lcp(s_i, t_i)$,其中 lcp 表示最长公共前缀。

数据范围

对于 20 % 20 \% 20% 的数据,保证 q ≤ 1000 q \leq 1000 q1000,任意时刻 ∣ S ∣ , ∣ T ∣ ≤ 1 |S|, |T| \leq 1 S,T1

对于 50 % 50 \% 50% 的数据,保证任意时刻 ∣ S ∣ , ∣ T ∣ ≤ 3 |S|, |T| \leq 3 S,T3

另有 30 % 30 \% 30% 的数据,保证 q ≤ 80 , ∑ ∣ s t ∣ ≤ 500 q \leq 80, \sum |st| \leq 500 q80,st500

对于 100 % 100 \% 100% 的数据,保证 q ≤ 500000 , ∑ ∣ s t ∣ ≤ 2 × 1 0 6 q \leq 500000, \sum|st| \leq 2 \times 10^6 q500000,st2×106,所有字符均为小写字母。

题解

看到这道题里面有 l c p lcp lcp,我们就可以考虑往 t r i e trie trie 树上去考虑,于是便有了如下:
把每个字符串压入 t r i e trie trie 树,然后考虑每个字符的贡献,如果另一个集合内的当前位置所拥有的串比这个集合内的多,那么这个字符就是有贡献的,贡献为1.
删除也同理,于是答案就可以动态维护了。

代码

#include<bits/stdc++.h>
using namespace std;
const int N=2e6+10;
int n,q,t[2][26][N],qu1[N],nxt[N][26],sz[2][N],tot,ans,k;
string qu2[N];
void insert(int pos,string ck){
	k=0;
	for(int i=0;i<ck.size();++i){
		if(!nxt[k][ck[i]-'a'])nxt[k][ck[i]-'a']=++tot;
		k=nxt[k][ck[i]-'a'];
		if(sz[pos^1][k]>sz[pos][k])ans++;
		sz[pos][k]++;
	}
}
void del(int pos,string ck){
	k=0;
	for(int i=0;i<ck.size();++i){
		k=nxt[k][ck[i]-'a'];
		if(sz[pos][k]<=sz[pos^1][k])ans--;
		sz[pos][k]--;
	}
}
int main(){
	ios::sync_with_stdio(false);
	cin>>q;
	for(int i=1;i<=q;++i){
		int type,p;string ck;char x;
		cin>>type;
		if(type==1){
			cin>>x>>ck;
			if(x=='T')p=1;
			else p=0;
			//cout<<"FAQ "<<endl;
			insert(p,ck);
			qu1[i]=p,qu2[i]=ck;
		}
		else{
			cin>>p;
			//cout<<"FAQ "<<qu1[p]<<" "<<qu2[p]<<endl;
			del(qu1[p],qu2[p]);
		}
		printf("%d\n",ans);
	}
	return 0;
}
/*
4 
1 S aaab
1 T abccab
1 T aaab
2 3
*/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值