F. Paper Grading
题意:
有
2
e
5
2e5
2e5个字符串和
2
e
5
2e5
2e5个操作;
第一种操作是 交换两个字符串;
第二种是 给你
l
,
r
,
k
l,r,k
l,r,k 和一个字符串
s
s
s ,询问 区间
l
到
r
l到r
l到r 中有多少个字符串的前
k
k
k个字符 和
s
s
s的前
k
k
k个字符相同。
思路:
先将所有字符串建成一颗
t
r
i
e
trie
trie树,在字符串的结尾位置打个标记。
然后 询问下标
l
到
r
l到r
l到r之间有多少个字符串 和
s
s
s的前
k
k
k 个字符相同,就转换成了 询问
t
r
i
e
trie
trie树的一颗子树中 有多少个结束点 在
l
到
r
l到r
l到r之间,询问一颗子树 可以用
d
f
s
dfs
dfs序 转换成询问区间的问题:那么操作二就转换成了经典的 求
L
到
R
L到R
L到R 中
l
到
r
l到r
l到r 的和。还有操作一的修改操作,可以用树套树实现,就
O
K
OK
OK 啦~
当然当然CDQ分治肯定也是没问题的啦~
o p s : ops: ops:数据结构没学好,每次遇到这种题,都会去想 带修可持久化,后来发现这个东西好像 子虚乌有;一般带修可持久化是用树套树来实现,即树状数组套动态开点线段树,支持的是单点修改。
代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll mod=1e9+7;
int n,m;
int trie[200060][26];
int tot=1,cnt=0;
int ed[200060],dfn[200050],id[200050];
char s[200050];
struct node{
int ls,rs,num;
}tr[30000050];
int siz[200050],root[200050];
void insert(int i){
int now=1;
int len=strlen(s);
for(int i=0;i<len;i++){
if(trie[now][s[i]-'a']);
else {
trie[now][s[i]-'a']=++tot;
}
now=trie[now][s[i]-'a'];
}
ed[i]=now;
}
void dfs1(int i){
dfn[++cnt]=i;id[i]=cnt;
siz[i]=1;
for(int j=0;j<26;j++){
if(trie[i][j])dfs1(trie[i][j]),siz[i]+=siz[trie[i][j]];
}
}
void update(int &rt,int l,int r,int x,int w){
if(!rt)rt=++tot;
tr[rt].num+=w;
if(l==r)return;
int mid=l+r>>1;
if(x<=mid)update(tr[rt].ls,l,mid,x,w);
else update(tr[rt].rs,mid+1,r,x,w);
}
int query(int rt,int l,int r,int x,int y){
if(!rt)return 0;
if(x<=l&&r<=y)return tr[rt].num;
int mid=l+r>>1,ans=0;
if(x<=mid)ans+=query(tr[rt].ls,l,mid,x,y);
if(mid<y)ans+=query(tr[rt].rs,mid+1,r,x,y);
return ans;
}
int lowbit(int x){
return x&(-x);
}
void add(int x,int pos,int w){
while(x<=n){
update(root[x],1,cnt,pos,w);
x+=lowbit(x);
}
}
int ask(int x,int l,int r){
int ans=0;
while(x){
ans+=query(root[x],1,cnt,l,r);
x-=lowbit(x);
}
return ans;
}
int get(int k){
int now=1;
for(int i=0;i<k;i++){
if(trie[now][s[i]-'a'])now=trie[now][s[i]-'a'];
else return 0;
}
return now;
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%s",s);
insert(i);
}
dfs1(1);
tot=0;
for(int i=1;i<=n;i++){
add(i,id[ed[i]],1);
}
while(m--){
int op;
scanf("%d",&op);
if(op==1){
int a,b;scanf("%d%d",&a,&b);
add(a,id[ed[a]],-1);
add(a,id[ed[b]],1);
add(b,id[ed[a]],1);
add(b,id[ed[b]],-1);
swap(ed[a],ed[b]);
}else{
int a,b,k;
scanf("%s%d%d%d",s,&k,&a,&b);
k=get(k);
if(k==0)printf("0\n");
else{
printf("%d\n",ask(b,id[k],id[k]+siz[k]-1)-ask(a-1,id[k],id[k]+siz[k]-1));
}
}
}
return 0;
}