随笔分类 - 数据结构
摘要:很早就会了splay。。。但是这题一直没有AC....解法:按照顺序把节点旋到根,然后给根的左儿子打个标记,删掉根...疑问?最开始的时候直接去找根节点前趋和后继节点的标号,然后两个splay删掉根。。。一直没调出来,不知到为什么错,后来的时候通过select找rank就AC了。。。难道是树的形状和我预想的不对?不明。。 1 #include 2 #include 3 #include 4 #include 5 #include 6 #include 7 #include 8 #include 9 #include 10 #include 11 #include 12 #in...
阅读全文
摘要:题意 给出n(n 2 #include 3 #include 4 #include 5 using namespace std; 6 const int N = 1010; 7 const int inf = ~0u>>2; 8 int hash[129]; 9 struct node{ 10 node *ch[4],*fail; 11 int mask; 12 void clear(){ 13 for(int i = 0;i clear(); 25 return p; 26 } 27 void ini...
阅读全文
摘要:和poj 1625一样,不同的是长度变长了 先考虑另外一个问题,给你一个有向图,从某个点出发走n步到其他任意点,问不同的走法。 对这个问题构造一个矩阵,matrix[i][j]表示从i到j有几条边,然后这个矩阵自乘n次就是答案。 再说这个问题, Trie图本身就是一个有向图,那么一个长度为n的字符串相当于从根节点沿着边走n步。。。所以和上面那个问题一样。。构造矩阵的时候要注意边不能有非法节点。 可以在构造矩阵时去掉非法节点的行和列来优化。。(这里我没去掉。。。 1 #include 2 #include 3 #include 4 #include 5 using name...
阅读全文
摘要:题意: 给你一个字典,还有一些非法串,利用字典中的字符组成长度为m的不含非法串的字符串,求方案数。解法: 坑了我一整天我擦。。。。 因为自动机本身就是一个状态转移图,所以在上面进行DP很好理解,dp[i][j]记录长度为i并且走到DFA中j节点的方案数。。 需要注意的是非法节点是不能走的,在建Trie图的时候也要注意,如果当前节点的fail节点是非法的,那么这个点也是非法的,因为这个串包含了某个非法串。。。 1 #include 2 #include 3 #include 4 #include 5 #include 6 using namespace std; 7 con...
阅读全文
摘要:题意: 给一个1e5长只有小写字母的串,1e5个询问,问某个串在可以重叠或者不可以重叠的条件下最大匹配数。解法: 最开始的时候在Trie的每个节点把所有出现的单词编号全塞到vector里,结果TLE到死。其实如果在插入的时候,以同一个节点作为终止节点的只有那一个。。所以对一个串只插入一次就行,然后自动机匹配的时候分别统计可以重叠和不可以重叠的匹配数。 可以重叠的匹配只要在自动机上跑就行,对于不可以重叠的,记录一下上次匹配的位置,然后判断一下是否满足条件就行。。 字符串判重的时候我写了个双重hash。。。 1 #include 2 #include 3 #include 4 #i...
阅读全文
摘要:解法: 在对树的dfs同时维护两颗线段树,记录到达当前节点经过左路径和右路径上的权值,然后注意回退的时候要删除。。。 1 #include 2 #include 3 #include 4 #include 5 #pragma comment(linker, "/STACK:102400000,102400000") 6 using namespace std; 7 #define lson l,m,nG[N]; 15 vectorV[N]; 16 int w[N]; 17 pairans[N]; 18 struct segtree{ 19 int s[N>1; 27
阅读全文
摘要:解法: 对于第二个串,循环移动能得到的字典序最小的串,可以直接用最小表示法搞定。 然后用最小表示的第二个串和第一个串做两次扩展KMP,一次正常求,另外一次将两个串都反转一下,然后扫一遍ex[]数组 1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 const int N = (int)2e6+10; 6 char a[N],b[N],c[N]; 7 int next[N],exa[N],exb[N]; 8 void getnext(cha
阅读全文
摘要:这题和这个是一样的,唯一的不同是内存限制变小了今天学到了一种函数式线段树成段更新时节约内存的办法 。。。先考虑朴素的仅支持成段加减的线段树,我们可以用方式解决:1.正常的懒惰标记,当访问到带有懒惰标记节点的子区间时将标记下传;2.不用下传的懒惰标记,我们用一个标记来记录当前节点的整段区间被累加了多少,当询问的时候我们在从根节点走到目标结点的过程中不断累加所经过节点上的标记值。。。基于这两种思想,就有了函数式线段树的两种实现方式,第一种在pushdown的过程中会产生大量的结点,而第二种没有pushdown的过程,不会新建过多的节点 1 #include<cstdio> 2 #inc
阅读全文
摘要:题意: 带询问历史版本的线段树>_<解法: 主席树的成段更新,除了线段树成段更新的懒惰标记之外还要用一个懒惰标记来记录当前节点和其子节点是否是同一个版本的,如果不是的话,在pushdown的过程中要新建两个新节点,别的没什么了>_< p.s.主席树的内存消耗真是叹为观止。。。hdu4348徘徊在MLE和RE之间。。。 1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std;
阅读全文
摘要:题意: 求某段区间内不同元素之和。解法: 离线处理,将待询问区间按照右端点排序,然后依次将元素插入到线段树中,为了保证求得的结果都是不同元素之和,我们需要保证同一时刻某个元素在线段树中只能出现一次,如果之前插入了,那就先删除再在新位置插入。 p.s.这题函数式线段树应该可以在线做,但是暂时没想到>_< 1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 typedef lon
阅读全文
摘要:题意:无修改的区间第k小问题。p.s.终于能用三种方法搞定这道题了,开心~ 划分树的方法喜闻乐见; 线段树套平衡树然后二分枚举答案,写起来比较麻烦; 今天刚刚想明白函数式线段树>_<,发现写这个还挺方便; 1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 const int N = (int)3e6+10; 6 const int maxn = (int)1e5; 7 int lson[N],rson[N],sum[N]; 8
阅读全文
摘要:区间第k大问题,因为这个是动态的,有修改,所以划分树是搞不定的。第一次写树套树,也就是线段树套平衡树,线段树的每个节点是一个平衡树。查询的时候二分枚举答案,然后判断当前枚举的数是不是第k大的。这里我的平衡树选择的是treap,但是释放空间那儿写的好丑。。。 1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 const int inf=~0u>>1; 6 const int N=(int)1e5+10; 7 const int
阅读全文
摘要:解法:splay显而易见 除了REVOLVE操作,其它的都是splay的常规操作。 REVOLVE操作可以用三次翻转操作来实现。。。如果要实现区间[a,b][b+1,c]的交换,可以依次翻转[a,b],[b+1,c],[a,b]。。。。p.s.换了下splay的代码风格。。瞬间感觉清新明快不少。。。。 1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 const int N = (int)1e6+10; 6 const int inf=~
阅读全文
摘要:p.s.我只是拿来练treap的。。。treap比SBT真心好写啊。。。又参考了一下别人的treap写法。。真心飘逸。。。。学习之。。。 1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<iostream> 5 #include<string> 6 #include<vector> 7 #include<set> 8 #include<map> 9 #include<vector> 10 #in
阅读全文
摘要:题意:...解法:树链剖分,对点进行重编号,这样的话线段树中点的信息就是树中点的信息。。。别的很常规。。。 1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #define N 30010 5 #define lson l,m,n<<1 6 #define rson m+1,r,n<<1|1 7 using namespace std; 8 const int inf=1<<30; 9 struct Edge{ 10 int u,v,next; 1
阅读全文
摘要:题意:给一棵节点数不超过10000的树,有三种操作: 1.询问a,b路径上最大的边权; 2.修改第i条边的边权; 3.将a->b路径上所有边的边权取反。解法: spoj375加强版,将点映射到线段树之后,需要用线段树的成段更新来支持操作三,其余的和spoj那题做法一样。 1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #define N 10010 5 #define lson l,m,n<<1 6 #define rson m+1,r,n<<1|1
阅读全文
摘要:题意:给一棵树,节点数不超过10000,有两个操作:1.询问a,b路径上最长的边长。2.把第a条边长度改为b.p.s.人生中第一个树链剖分,尼玛debug了好久好久我擦。。。分析:轻重边路径剖分,把点都映射到线段树上搞之。。。具体的东西等我刷一刷题之后一起写个总结吧o(╯□╰)o 1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<iostream> 5 #define N 10010 6 #define lson l,m,n<<1 7 #de
阅读全文
摘要:题意:给定一个含有n个数的序列,从中找出连续长度不超过k的非空子序列,使其和最大。(n<=10^5,k<=10^5)解法:考虑最朴素的做法,用maxn[i]表示以i为结尾,长度不超过k的非空子序列的最大和,那么有maxn[i]=sum[i]-max{sum[i-1]...sum[i-k]},直接做的话时间复杂度O(n*k),看到表达式中后一部分,可以采用单调队列解决,维护一个sum[i]单调递增的单调队列,那么每次求解maxn[i]就可以直接取队列头,复杂度降到O(1),由于长度不大于k,所以每次插入之后还要删掉不满足条件的队头元素。。。 1 #include<cstdio&
阅读全文
摘要:题目描述: 给定连续的内存块,支持4个操作: 1.申请连续长为x的空间,并且返回这段区间的左端点。 2.释放包含x的内存块。 3.询问从左到右第x块的区间范围。 4.重置。分析: 和poj3667比较像,只是多了3 4的操作。 我开了两个线段树,第一个成段更新,为了记录每一段的颜色(其实就是第几次申请时被占用的),第二个记录每一段起点,这是为了方便操作3的查询。 最后reset的时候传一个懒惰标记就行。。重新build会超时 p.s.数组大小随便开的。。。其实可以小点。。无视就好 1 #include<iostream> 2 #include<cstdio...
阅读全文
摘要:题目描述:给定连续的n个村庄,有三种操作: 1.D x:毁掉第x个村庄; 2.Q x:询问直接或间接与x相连的村庄数目 3.R :恢复上一个被毁掉的村庄。分析:用线段树维护区间内以左端点开始的连续区间,以右端点结束的连续区间。 询问我拆成了两部分,一个是询问x向右(含x)的连续区间长,一个是询问x向左(含x)的连续区间长,加和减一就是答案。 操作三用个栈记录下就行。 1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 #defin.
阅读全文

浙公网安备 33010602011771号