题目链接:
http://codeforces.com/gym/101161/attachments
题意:
给一个可以变化的字典树
在字典树上删边
如果某条边和根节点不连通那么这条边也删除
谁没得删就输了
数据范围:
$1\leq n \leq 100000$
$1\leq q \leq 100000$
$1\leq |s| \leq 40$
分析:
先对当前字符串建立字典树
每个玩家的操作其实就是删除字典树的一个子树,相当于树上删边游戏
结论:
叶子节点:$sg=0$
其他节点:sg=(所有孩子节点sg+1)的异或和
ac代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define pii pair<int,int>
const int maxn = 1e5+7;
int sg[maxn*41],son[maxn*41][26],f[maxn*41],cnt;
char s[45];
int ins(){
int now=0;
int len=strlen(s+1);
for(int i=1;i<=len;i++){
int v=s[i]-'a';
if(son[now][v])now=son[now][v];
else {
cnt++;
f[cnt]=now;
son[now][v]=cnt;
now=cnt;
sg[cnt]=len-i;
if(i==len)
return cnt;
}
}
return 0;
}
void up(int x){
sg[x]=0;
for(int i=0;i<26;i++)
if(son[x][i])sg[x]^=(sg[son[x][i]]+1);
if(x==0)return ;
up(f[x]);
}
int main()
{
int T,n,q;
scanf("%d",&T);
for(int cas=1;cas<=T;cas++){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%s",s+1);
int v=ins();
up(v);
}
scanf("%d",&q);
printf("Case %d:\n",cas);
while(q--){
scanf("%s",s+1);
int v=ins();
up(v);
if(sg[0])printf("1\n");
else printf("2\n");
}
for(int i=0;i<=cnt;i++)
for(int j=0;j<26;j++)son[i][j]=0;
cnt=0;
}
return 0;
}