DTOJ#5127. 字串

csdnzhanghongyu發表於2020-11-05

你有兩個字串可重集合 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 \in S, t_i \in T,S, T siS,tiTS,T 中的每個元素最多出現在一個二元組中。

定義集合 S , T S, T S,T 一組匹配方案的權值為,$ \sum lcp(s_i, t_i)$,其中 l c p lcp lcp 表示最長公共字首。

第一行輸入 q q q,表示操作次數。

接下來 q q q 行,每行先輸入一個 t y p e type type

  • t y p e = 1 type = 1 type=1,表示一次插入操作,接著讀入 c , s t c, st c,st c ∈ { S , T } c \in \{S, T\} c{S,T} 表示插入的集合, s t st st 為插入的字串。

  • t y p e = 2 type = 2 type=2,表示一次刪除操作,接著讀入 k k k,表示刪除第 k k k 次操作插入的字元(保證第 k k k 次是插入,且未被刪除)。

q q q 行,每行輸出一個數,表示這次操作完後的最大權匹配。

樣例輸入

7
1 S aaab
1 T abccab
1 T ac
1 S abccde
2 4
1 S acc
1 T aaa

樣例輸出

0
1
1
5
1
3
5

樣例解釋

2 2 2 次操作完後,匹配為 ( a a a b , a b c c a b ) (aaab,abccab) (aaab,abccab)

4 4 4 次操作完後,匹配為 ( a a a b , a c ) , ( a b c c d e , a b c c a b ) (aaab,ac),(abccde,abccab) (aaab,ac),(abccde,abccab)

7 7 7 次操作完後,匹配為 ( a a a b , a a a ) , ( a c c , a c ) (aaab,aaa),(acc,ac) (aaab,aaa),(acc,ac)

對於 20 % 20 \% 20% 的資料,保證 q ≤ 1000 q \leq 1000 q1000,任意時刻 ∣ S ∣ , ∣ T ∣ ≤ 1 \lvert S\rvert, \lvert T\rvert \leq 1 S,T1

對於 50 % 50 \% 50% 的資料,保證任意時刻 ∣ S ∣ , ∣ T ∣ ≤ 3 \lvert S|, \lvert T\rvert \leq 3 S,T3

另有 30 % 30 \% 30% 的資料,保證 q ≤ 80 , ∑ ∣ s t ∣ ≤ 500 q \leq 80, \sum \lvert st\rvert \leq 500 q80,st500

對於 100 % 100 \% 100% 的資料,保證 q ≤ 500000 , ∑ ∣ s t ∣ ≤ 2 × 1 0 6 q \leq 500000, \sum\lvert st\rvert \leq 2 \times 10^6 q500000,st2×106,所有字元均為小寫字母。

首先最暴力的做法就是 n 2 n^2 n2列舉,考慮優化。
我們把列舉操作放到 t r i e trie trie樹上,可以發現,我們遍歷到某一個節點,滿足字首已匹配,所以當前點一定可以匹配。考慮交換操作,這時發現 t r i e trie trie樹若當前結點還支援匹配,則匹配操作相當於交換。。
所以貪心是正確的。

#include<bits/stdc++.h>
#define N 2000006
using namespace std;
int t[N][26],tot=1,cnt[N],ans,ty[N][2];
vector<char> in[N];
inline void add(int to,int val){
	int w=1;
	for(int i=0;i<in[to].size();++i){
		int c=in[to][i]-'a';
		if(!t[w][c])t[w][c]=++tot;
		w=t[w][c];
		if(cnt[w]*val<0)ans++;
		cnt[w]+=val;
	}
}
char ss[N],s[5];
int ad[2]={-1,1},len;
int main(){
	int q,it=0;scanf("%d",&q);
	for(int i=1;i<=q;++i){
		int op;scanf("%d",&op);
		if(op==1){
			scanf("%s%s",s,ss);++it;len=strlen(ss);
			for(int j=0;j<len;++j)in[it].push_back(ss[j]);
			ty[i][0]=(s[0]=='S');ty[i][1]=it;
			add(it,ad[s[0]=='S']);
		}else{
			scanf("%d",&op);add(ty[op][1],-ad[ty[op][0]]);ans-=in[ty[op][1]].size();
		}
		printf("%d\n",ans);
	}
}

相關文章