BZOJ2690 : 字符串游戏

离线算法:

先将所有涉及到的串建成字典树,然后用线段树维护dfs序,时间复杂度$O(m\log L)$。

在线算法:

用替罪羊树动态维护Trie树的dfs序即可,时间复杂度$O(L\log L)$。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=2100010,M=50010;const double A=0.77;
int Type,n,m,i,x,y,loc[M],w[M],trie[N>>1][26],st[N>>1],en[N>>1],ct,ans;
char op[5],s[N];
namespace Subtask1{
int cnt,dfn,v[N],tag[N],c,d,p;
struct P{int x,y;P(){}P(int _x,int _y){x=_x,y=_y;}}q[250010];
void dfs(int x){
  st[x]=++dfn;
  for(int i=0;i<26;i++)if(trie[x][i])dfs(trie[x][i]);
  en[x]=dfn;
}
inline void tag1(int x,int p){v[x]+=p;tag[x]+=p;}
void change(int x,int a,int b){
  if(c<=a&&b<=d){tag1(x,p);return;}
  if(tag[x])tag1(x<<1,tag[x]),tag1(x<<1|1,tag[x]),tag[x]=0;
  int mid=(a+b)>>1;
  if(c<=mid)change(x<<1,a,mid);
  if(d>mid)change(x<<1|1,mid+1,b);
  v[x]=max(v[x<<1],v[x<<1|1]);
}
inline void insert(int p){
  gets(s);
  int l=strlen(s);register int x=0,i=0;
  for(int w;i<l;i++)if(s[i]>=‘a‘){
    if(!trie[x][w=s[i]-‘a‘])trie[x][w]=++ct;
    x=trie[x][w];
  }
  loc[p]=x;
}
void work(){
  for(i=1;i<=n;i++)insert(i);
  for(i=1;i<=n;i++)scanf("%d",&w[i]),q[++cnt]=P(loc[i],max(w[i],0));
  while(m--){
    scanf("%s",op);
    if(op[0]==‘Q‘)q[++cnt]=P(-1,0);
    if(op[1]==‘v‘){
      scanf("%d%d",&x,&y);
      q[++cnt]=P(loc[x],max(y,0)-max(w[x],0));
      w[x]=y;
    }
    if(op[1]==‘s‘){
      scanf("%d",&x);
      if(w[x]>0)q[++cnt]=P(loc[x],-w[x]);
      insert(x);
      if(w[x]>0)q[++cnt]=P(loc[x],w[x]);
    }
  }
  dfs(0);
  for(i=1;i<=cnt;i++)if(q[i].x<0)printf("%d\n",v[1]);else c=st[q[i].x],d=en[q[i].x],p=q[i].y,change(1,1,dfn);
}
}
namespace Subtask2{
int size[N],son[N][2],val[N],h[N],tag[N],f[N],tot,root,data[N],id[N],cnt;
int P,B,C,D;
inline void umax(int&a,int b){if(a<b)a=b;}
inline int newnode(int x,int p,int fa){
  f[x]=fa;size[x]=1;son[x][0]=son[x][1]=0;
  h[x]=val[x]=p;tag[x]=0;
  return x;
}
inline void tag1(int x,int p){h[x]+=p;val[x]+=p;tag[x]+=p;}
inline void pb(int x){
  if(tag[x]){
    if(son[x][0])tag1(son[x][0],tag[x]);
    if(son[x][1])tag1(son[x][1],tag[x]);
    tag[x]=0;
  }
}
inline void up(int x){
  h[x]=val[x];
  if(son[x][0])umax(h[x],h[son[x][0]]);
  if(son[x][1])umax(h[x],h[son[x][1]]);
}
int ins(int x){
  size[x]++;pb(x);
  if(!son[x][B])return son[x][B]=newnode(++tot,P,x);
  return ins(son[x][B]);
}
void dfs(int x){
  pb(x);
  if(son[x][0])dfs(son[x][0]);
  data[++cnt]=val[x];id[cnt]=x;
  if(son[x][1])dfs(son[x][1]);
}
int build(int fa,int l,int r){
  int mid=(l+r)>>1,x=newnode(id[mid],data[mid],fa);
  if(l==r)return x;
  if(l<mid)size[x]+=size[son[x][0]=build(x,l,mid-1)];
  if(r>mid)size[x]+=size[son[x][1]=build(x,mid+1,r)];
  return up(x),x;
}
inline int rebuild(int x){cnt=0;dfs(x);return build(f[x],1,cnt);}
inline int kth(int k){
  register int x=root,rank,t;
  while(1){
    size[x]++;pb(x);
    rank=size[son[x][0]]+1;
    if(k==rank)return x;
    if(k<rank)x=son[x][0];else k-=rank,x=son[x][1];
  }
}
inline int rank(register int x){
  int ans=size[son[x][0]]+1;
  while(f[x]){
    if(son[f[x]][1]==x)ans+=size[son[f[x]][0]]+1;
    x=f[x];
  }
  return ans;
}
inline void kthins(int k){
  register int x=kth(k);
  if(son[x][0])B=1,x=ins(son[x][0]);else{
    son[x][0]=newnode(++tot,P,x);
    x=son[x][0];
  }
  while((double)size[son[x][0]]<A*size[x]&&(double)size[son[x][1]]<A*size[x])x=f[x];
  if(!x)return;
  if(x==root){root=rebuild(x);return;}
  int y=f[x],b=son[y][1]==x,now=rebuild(x);
  son[y][b]=now;
}
inline void modify(int x,int a,int b){
  if(!x)return;
  if(C<=a&&b<=D){tag1(x,P);return;}
  pb(x);
  int mid=a+size[son[x][0]];
  if(C<=mid&&mid<=D)val[x]+=P;
  if(C<mid)modify(son[x][0],a,mid-1);
  if(D>mid)modify(son[x][1],mid+1,b);
  up(x);
}
inline int getval(int x){
  cnt=0;
  for(register int i=x;i;i=f[i])id[++cnt]=i;
  while(cnt)pb(id[cnt--]);
  return val[x];
}
inline void addleaf(int x,int y){
  int k=rank(en[x]);P=getval(en[x]);
  st[y]=tot+2,en[y]=tot+1;
  kthins(k);
  kthins(k);
}
inline void subtreeadd(int x,int y){C=rank(st[x]),D=rank(en[x]),P=y;modify(root,1,tot);}
inline void insert(int p){
  gets(s);
  int l=strlen(s);register int x=0,i=0;
  for(int w;i<l;i++)if(s[i]>=‘a‘){
    w=(s[i]-‘a‘+ans)%26;
    if(!trie[x][w])addleaf(x,trie[x][w]=++ct);
    x=trie[x][w];
  }
  loc[p]=x;
}
void work(){
  root=build(0,st[0]=id[1]=1,tot=en[0]=id[2]=2);
  for(i=1;i<=n;i++)insert(i);
  for(i=1;i<=n;i++)scanf("%d",&w[i]),subtreeadd(loc[i],max(w[i],0));
  while(m--){
    scanf("%s",op);
    if(op[0]==‘Q‘)printf("%d\n",ans=h[root]);
    if(op[1]==‘v‘){
      scanf("%d%d",&x,&y);
      y=min(1000,y+ans%1000);
      subtreeadd(loc[x],max(y,0)-max(w[x],0));
      w[x]=y;
    }
    if(op[1]==‘s‘){
      scanf("%d",&x);
      if(w[x]>0)subtreeadd(loc[x],-w[x]);
      insert(x);
      if(w[x]>0)subtreeadd(loc[x],w[x]);
    }
  }
}
}
int main(){
  scanf("%d%d%d",&Type,&n,&m);gets(s);
  if(Type==1)Subtask1::work();else Subtask2::work();
  return 0;
}

  

时间: 2024-08-03 16:26:27

BZOJ2690 : 字符串游戏的相关文章

BZOJ2121 字符串游戏

Description BX正在进行一个字符串游戏,他手上有一个字符串L,以及其 他一些字符串的集合S,然后他可以进行以下操作:对于一个在集合S中的字符串p,如果p在L中出现,BX就可以选择是否将其删除,如果删除,则将删除后L 分裂成的左右两部分合并.举个例子,L='abcdefg' , S={'de'},如果BX选择将'de'从L中删去,则删后的L='abcfg'.现在BX可以进行任意多次操作(删的次数,顺序都随意),他想知道最 后L串的最短长度是多少. Input 输入的第一行包含一个字符串

QuickHit项目(输出字符串游戏)

public class leve { private int leveNo; private int strLength; private int strTimes; private int timeLimit; private int perScore; public leve(int leveNo, int strLength, int strTimes, int timeLimit, int perScore) { super(); this.leveNo = leveNo; this.

字符串游戏(strgame)——博弈

题目 [题目描述] pure 和 dirty 决定玩 $T$ 局游戏.对于每一局游戏,有 $n$ 个字符串,并且每一局游戏由 $K$ 轮组成.具体规则如下:在每一轮游戏中,最开始有一个空串,两者轮流向串的末尾添加一个字符,并且需要保证该串为 $n$ 个字符串中任意一个串的前缀,不能操作的人输掉这一轮,并且在下一轮游戏中由该轮输掉的人先手.另外为了遵循女士优先的原则,在每一局游戏的第一轮均由 pure 先手. 玩家的目标是获得整局游戏的胜利,一局游戏的胜利条件是:对手输掉最后一轮游戏.我们可以假定

【bzoj2121】字符串游戏 区间dp

题目描述 给你一个字符串L和一个字符串集合S,如果S的某个子串在S集合中,那么可以将其删去,剩余的部分拼到一起成为新的L串.问:最后剩下的串长度的最小值. 输入 输入的第一行包含一个字符串,表示L. 第二行包含一个数字n,表示集合S中元素个数. 以下n行,每行一个字符串,表示S中的一个元素. 输入字符串都只包含小写字母. 输出 输出一个整数,表示L的最短长度. 样例输入 aaabccd3acabcaaa 样例输出 2 题解 我们考虑:每次删除连续的一段,对应到原串上即:删除 $[l,r]$ 中所

BZOJ2121 字符串游戏 【dp】

题目链接 BZOJ2121 题解 dp怎么那么神呐QAQ 我们要求出最小字符串长度 我们设一个\(dp[i]\)表示前\(i\)个字符最后所形成的最短字符串长度 对于第\(i\)个字符,要么保留,就是\(dp[i] = dp[i - 1]\),要么和前面若干个字符一起被删掉 我们设\(c[i][j]\)表示区间\([i,j]\)能否被删掉 如果我们能求出\(c[i][j]\)就好了 我们再设一个\(f[i][j][k][t]\)表示区间\([i,j]\)能否匹配第\(k\)个串的前\(t\)个字

bzoj5147&amp;&amp;bzoj2121&amp;&amp;loj6701 字符串游戏

做不出来杂题,到处找题做 看到$loj$上新出了一道题,觉得很神仙不错, 还记得Censoring吗(一个AC自动机的题) 这个题求最优解,数据范围$150$ 题解 数据范围非常小,首先贪心肯定不行,考虑AC自动机上$dp$? 好吧其实是区间$dp$ 一个直接的想法是维护$f[l][r]=0/1$表示是否可以清空$l$,$r$这一段子段 然而转移起来很难转移,考虑再定义一个数组$g[l][r][i][w]=0/1$表示是否可以清成第$i$个模式串的前$w$位 考虑$g$转移, 1.直接匹配$g[

UVA 12378 Ball Blasting Game Manacher裸题

消除字符串游戏,选择一个字母,则会消除和该字母相同且连续的一段,然后左右两边合拢,若左右两边字母相同则再次消除掉.直到合拢时两边字母不相同. 问这样连续消除的最大次数. 思路: 先把连续相同的字母当成一个字母,然后求最长回文串, 则答案就是(最长长度+1)/;2 [cpp] view plaincopy #pragma comment(linker, "/STACK:1024000000,1024000000") #include <cstdio> #include <

UPC OJ 一道水题 STL

Problem C: 字符串游戏 Time Limit: 1 Sec  Memory Limit: 128 MB Submit: 10  Solved: 3 [Submit][Status][Web Board] Description 说到游戏,大家还是比较喜欢的,但是玩游戏,如果想赢得对方还是得靠思维的,xy比较喜欢字符串,尤其是起始字母等于终止字母这样的字符串(the string's length must exceed one),但是呢,xy有个癖好,喜欢把每个字符重新分配一个值,喜欢

计数类问题专题

主要是前两天被uoj的毛爷爷的题虐的不轻,心里很不爽啊,必须努力了,, 计数类问题分为:1.组合数学及数论计数 2.dp:状态压缩dp,插头轮廓线dp,树形dp,数位dp,普通dp 3.容斥原理 4.polya原理 5.图论计数 6.生成函数 7.其它(生成树计数等等) 本文主要研究前3个内容 考虑基本计数原理:加法原理,减法原理,乘法原理,除法原理 计数的基本原则:结果不重不漏 加法原理比较自然,中间过程有时减法原理 考虑到无向,有向图的各种量值(生成树之类)计数,状态压缩dp解决 论文:ht