BZOJ 十连测 可持久化字符串

SOL:

我们发现答案就是 跑一边KMP 那么答案就是i-net[i],

我们考虑在trie上跑KMP,我们发现KMP的复杂度是依赖摊还分析的线性复杂度。如果朴素的KMP做法时间复杂度是不对的。

比如这样一个trie:  a

|

a

|
                                a

/        \

b             b

复杂度就退化了。那么我们可以考虑对每一个节点开一个数组:

f[i] 记下当前的节点后查入i元素后的kmp值。

我们可以发现当前节点的f和其net的f是差不多的,只要将net的f  copy一遍 ,再讲net的后继插进来就好了。

我们可以用主席树来维护f

O(nlogn)

#include<bits/stdc++.h>
using namespace std;
#define sight(c) (‘0‘<=c&&c<=‘9‘)
#define N 300007
inline void read(int &x){
    static char c;
    for (c=getchar();!sight(c);c=getchar());
    for (x=0;sight(c);c=getchar())x=x*10+c-48;
}
void write(int x){if (x<10) {putchar(‘0‘+x); return;} write(x/10); putchar(‘0‘+x%10);}
inline void writeln(int x){ if (x<0) putchar(‘-‘),x*=-1; write(x); putchar(‘\n‘); }
inline void writel(int x){ if (x<0) putchar(‘-‘),x*=-1; write(x); putchar(‘ ‘); }
struct Node{
    int l,r,x;
}te[N<<5];
int tot,anw,n,m,op,fr,at,lastans,l,len[N],rot[N],fp[N],opt,Le;
int f[N][21];
#define Mid (l+r>>1)
void ins(int X,int & now,int l,int r,int id,int x) {
    now=++tot; te[now]=te[X];
    if (id==Mid) {te[now].x=x;return;}
    if (id<Mid) ins(te[X].l,te[now].l,l,Mid-1,id,x);
    else ins(te[X].r,te[now].r,Mid+1,r,id,x);
}
void que(int X,int l,int r,int x){
    if (Mid==x) {anw=te[X].x; return;}
    if (x<Mid) que(te[X].l,l,Mid-1,x);
    else que(te[X].r,Mid+1,r,x);
}
signed main () {
    freopen("string.in","r",stdin);
    freopen("string.out","w",stdout);
    read(n); read(m); read(op);
    for (int i=1;i<=n;i++) {
        read(fr); read(at);
        if (op) fr^=lastans,at^=lastans;
        fp[i]=at; f[i][0]=fr; l=len[i]=len[fr]+1;
        for (int j=1;j<=20;j++) f[i][j]=f[f[i][j-1]][j-1];
        que(rot[fr],1,m,at);
        writeln(lastans=(l-len[anw]));
        opt=i; Le=len[anw]+1;
        for (int j=20;~j;j--) if (len[f[opt][j]]>=Le) opt=f[opt][j];
        ins(rot[anw],rot[i]=++tot,1,m,fp[opt],opt);
    }
    return 0;
}

原文地址:https://www.cnblogs.com/rrsb/p/8580477.html

时间: 2024-10-17 04:36:27

BZOJ 十连测 可持久化字符串的相关文章

UI学习笔记---第十四天数据持久化

一.沙盒机制 每个应用程序位于文件系统的严格限制部分 每个应用程序只能在为该程序创建的文件系统中读取文件 每个应用程序在iOS系统内斗放在了统一的文件夹目录下 沙盘路径的位置 1. 通过Finder查找程序沙盘相对路径 ~/Library/Application Support/iPhone Simulator 2. 通过代码查找程序沙盘相对路径 NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory directory,NSSearc

noip2016十连测题解

以下代码为了阅读方便,省去以下头文件: #include <iostream> #include <stdio.h> #include <math.h> #include <string.h> #include <time.h> #include <stdlib.h> #include <string> #include <bitset> #include <vector> #include <

【C语言天天练(十八)】字符/字符串输入函数fgetc、fgets、getc、getchar和gets

#include <stdio.h> int fgetc(FILE *stream); char *fgets(char *s, int size, FILE *stream); int getc(FILE *stream); int getchar(void); char *gets(char *s); fgetc()读取文件指针stream所指向文件的下一个字符,返回值是所读取字符强制类型转换成整数的值,如果到达文件尾部或者出错,则返回EOF. getc()与fgetc()函数相同,只是它

c#编程指南(十) 平台调用P-INVOKE完全掌握, 字符串和指针

可以说新手使用P-INVOKE最开始的头疼就是C#和C++的字符串传递,因为这里涉及到两个问题. 第一:C#的string和C++的字符串首指针如何对应. 第二:字符串还有ANSI和UNICODE(宽字符串)之分. 本文分三部分阐述: 第一:字符串指针当输入参数, 第二:字符串指针作为返回值, 第三:字符串指针作为输入输出参数. C++部分的测试代码很简单这里就全部贴出来了: 1 #include "stdafx.h" 2 #include "TestDll.h"

Noi2016十连测第二场-黑暗 (二项式定理/斯特林数+CDQ+NTT)

Noi2016十连测第二场-黑暗 (二项式定理/斯特林数+CDQ+NTT) 题意: n 个点的无向图,每条边都可能存在,一个图的权值是连通块个数的 m 次方,求所有可能的图的权值和. 考虑\(dp[i][j]\)表示\(j\)个点,权值为\(i\)次方 我们首先要预处理出\(n\)个点无向联通图的数量\(g[i]\),模板题:BZOJ-3456 题解 对于\(dp[i][j]\),枚举\(1\)号点所在的连通块大小为\(x\),那么可以得到的是\(dp[i][j]=\sum dp[k][j-x]

bzoj [ 2017省队十连测推广赛1 ] ( 4765 &amp;&amp; 4766 &amp;&amp; 4767 )题解

bzoj 4765 -- 分块+dfs序+树状数组: 考虑分块.将1~n分成sqrt(n)块,对每个点记录它在每个块中的祖先个数,修改一个点时枚举每一块修改. 查询[l,r]时如果一个块在[l,r]中,直接将其加入答案.显然只剩下O(sqrt(n))个点.求出树的dfs序,用树状数组维护就可以O(logn)求出答案. 时间复杂度O(n*sqrt(n)*logn) 代码: 1 #include<iostream> 2 #include<cstdio> 3 #include<cs

[BZOJ]2017省队十连测推广赛1

听学长说有比赛就随便打一打. A.普通计算姬 题目大意:给出一棵带权树,支持一下两种操作:1.修改一个点的权值:2.给出l,r,询问以点l为根的子树和.点l+1为根的子树和.点l+2为根的子树和--点r为根的子树和的总和.(点数.操作数不超过10^5) 思路:感觉是三题中最难的.给出的[l,r]区间在树上没有实际意义,不好利用数据结构维护.考虑若不修改,可以一遍dfs算出每个点对应的dfs序,这样每棵子树都对应一个dfs序的区间,前缀和一下就能O(1)查子树和,再按点的编号顺序把子树和前缀和一下

bzoj省选十连测推广赛

A.普通计算姬 题意:给丁一棵树,每个点有一个权值,用sum(x)表示以x为根的子树的权值和,要求支持两种操作: 1 u v  :修改点u的权值为v. 2 l  r   :  求∑sum[i] l<=i<=r n,m(操作数)<=10^5 题解:数据范围比较小,考虑分块重建的做法. 求出每个点的dfs序和子树的区间,这样就可以On建出所有节点的sum的前缀和. 然后每次修改操作都把操作存下来,每次查询先找出这段区间的和,再去操作里处理这些操作对这个查询的影响. 具体实现就是:把每个点的子

BZOJ NOI十连测 第一测 T2

思路:看到这题,就感觉是一道很熟悉的题目: http://www.cnblogs.com/qzqzgfy/p/5535821.html 只不过这题的K最多可以到N,而且边权不再只是1,考试的时候yy了一下做法: 找k次直径,第一次把边取反,要是第二次再取到同样的边,那就把它变成0,毕竟每条边只经过2次嘛,YY的很好,实际上,交上去,5分TAT 后来听以为神犇说不是取0,而是继续取反,每条边取一次就取反一次,woc.. 1 #include<cstdio> 2 #include<cmath