11 2017 档案
摘要:线性基 非常高端 强制在线动态图 我们先搞出一个dfs树,然后所有非树边都和树边形成一个环。我们考虑什么情况会不连通,当且仅当树边和dfs序大于当前点的返祖边都被断掉才不连通,那么我们给每个非树边赋一个权值,树边的权值就是所有这些返祖边的权值的异或和,这样一遍dfs就行了。 然后就是怎么判断,因为树
阅读全文
摘要:树链剖分+差分 直接区间加显然是不行的,由于gcd(a,b,c)=gcd(a,a-b,b-c),那么我们对这些数差分,然后就变成单点修改。原本以为这道题很简单,没想到这么麻烦,就膜了发代码。 首先我们考虑如何在树上差分序列,每个节点有很多个儿子,如果把每个儿子都修改一下就GG了,其实我们可以这个样子
阅读全文
摘要:莫队+st表 据说这是经典问题,但是我不会。。。 问题在于莫队怎么算贡献,每次移动一个位置,现在为[l,r],那么就增加了[l-1,r),r的贡献,怎么算呢?我们预处理fl,fr,fl[i]表示以i为开头的前缀和,fr表示以i为结尾的后缀和,这个东西能够相减,但也不是完全满足 每次我们计算贡献的时候
阅读全文
摘要:状压dp 图上怎么跑dp?我们跑三进制状压dp,0表示选了,1表示既没选也没覆盖,2表示没选但是被覆盖了。 状态是dp[dep][S]表示当前走到了深度为dep的节点,状态为S,按照dfs序转移 每次转移就是计算这个点选了没选,然后像树形dp一样更新节点 返祖边也要处理 #include<bits/
阅读全文
摘要:二分图+矩阵求逆 既然我们考虑b能替换哪些a,那么我们自然要得出b被哪些a表示,这里我们设一个矩阵C,那么C*A = B 为什么呢?直接A*C = B是不可行的,因为都是行向量,不能直接乘,那么我们转置一下,得出At*C=Bt,这样就很科学了,那么再转回来,A*Ct=B,于是Ct=B*A^-1那么矩
阅读全文
摘要:最短路+最小生成树 因为所有东西都只跟加油站有关,那么我们只留加油站就行了。 先预处理出每个点到加油站的最短距离,这个用多源最短路,就是把所有加油站放到堆里,然后就是重构图,我们不用直接连边,计算出每条边的贡献,然后跑最小生成树,这里直接离线查询就行了。 #include<bits/stdc++.h
阅读全文
摘要:拓扑排序+set 如果我们直接记录所有路径是不行的,那么我们要降低路径的数量,于是我们把最短路径转换到边上,这样我们就只有m条路径了。 先计算出f[i]和g[i]表示正反拓扑最长链,把所有g插到set里,然后按照拓扑序依次枚举删点,把之前加入过的边删除,删除g[u],查询最大值,然后加入后继边每条边
阅读全文
摘要:动态电分治+二分 肯定要枚举所有点对,那么我们建出点分树降低树高,然后每个点存下点分树中所有子树到这个点的距离,然后二分+lower_bound就行了。 #include<bits/stdc++.h> using namespace std; const int N = 2e5 + 5; names
阅读全文
摘要:动态点分治 先建出点分树,每个点上维护两个堆,s1,s2,分别表示子树中到点分树中父亲的所有长度,每个儿子s1的最大值,那么对于每个点答案就是s2的最大+次大,再维护一个s3保存这个。 首先我们要搞一个带删除的堆,那么我们开两个堆就行了,一个保存元素,一个保存被删除的元素,每次一起弹出就行了 然后是
阅读全文
摘要:后缀自动机+线段树 今天比较颓。。。 既然只出现一次,那么就是right=1,于是我们预处理出每个点的right,然后看是否等于一,如果是就更新答案。 更新答案维护两个线段树,如果当前点在延伸[Min,Max]范围内,那么答案就是end-i+1,如果<Min,那么答案就是Min,于是我们维护end+
阅读全文
摘要:kdtree 转换一下,看成点,第一位dfs序,第二维深度,那么满足在子树内dfs序限制,然后kdtree上打标记就行了。 #include<bits/stdc++.h> using namespace std; const int N = 1e5 + 5, mod = 1e9 + 7; int r
阅读全文
摘要:kdtree 3维kdtree,就是三个维度轮换着切,我们把每个元素看成一个点,坐标是上次出现的位置,下次出现的位置,自己的位置,第一个<l,第二个>r,第三个[l,r],然后kdtree上爆搜剪枝就行了。 kdtree看起来能解决所有偏序问题。 #include<bits/stdc++.h> us
阅读全文
摘要:KD-tree **了这道题 这个估价函数好鬼畜,把min打成max。。。 关于min的估价函数非常鬼畜,具体我也不知道为什么。 #include<bits/stdc++.h> using namespace std; const int N = 5e5 + 5; int n, d, root, a
阅读全文
摘要:KD-tree 强制在线就不能愉快的做这道题了。 我们用KD-tree维护平面上的点,这样建出来的树高大概是log,复杂度过得去,但是插入过多会使树深很深,这样就能卡死,那么我们每个10000次插入就重构一次。 #include<bits/stdc++.h> using namespace std;
阅读全文
摘要:KD-tree+堆 多年大坑 KD-tree已经是半年前学的了,忘记了。这道题当时一直T,今天重新抄了一遍,A了 KD-tree过程:1.建树:每次依次按x,y划分平面,像二叉搜索树一样建树,每个点维护一些东西; 2.查询:直接查太暴力了,我们用估价函数减值,每个点维护最小最大的x和y,每次计算能够
阅读全文
摘要:广义后缀自动机+二分+单调队列+dp 这道题其实就是一个简单dp,dp[i]表示匹配到i最长匹配多少,设val[i]表示当前位置和原串的最长公共长度,二分的长度是L,那么要求dp[i]=max(dp[i-1],dp[j]+i-j)要求L<=i-j<=val[i],那么也就是j>=i-val[i],前
阅读全文
摘要:平衡树 6个操作做完当然GG了,其实只有两个操作,翻转[A+1,A+B],把这个区间放到C的后面,那么就是基本splay操作了,可是好久没打,又GG了,splay函数写错了。。。 #include<bits/stdc++.h> using namespace std; const int N = 1
阅读全文
摘要:树状数组+KMP 匹配问题上KMP 但是问题在于如何判断两个位置相等,我们认为如果一个位置之前比他小的数数量相同那么就是相等。 那么我们用树状数组动态维护这个东西,每次跳nxt的时候用树状数组删除数。因为每个数只加入一次,所以复杂度是nlogn的,为什么这样是对的呢?我们这么想,对于当前加入最后的一
阅读全文
摘要:后缀自动机+LCT 终于做了这道题 思路比较明显,每次的答案就是走到的最终节点的Right集合大小,如果走不到就是0。但是问题在于每次添加字符后parent树的形态变了,那么Right集合也要变化,这个我们用LCT维护,由于是有根树,比较好维护。 #include<bits/stdc++.h> us
阅读全文
摘要:广义后缀自动机 具体我也不是很清楚 像这样有很多个串要统计方案的题我们建一个广义后缀自动机,就是每次对一个串建完后把last设为root,然后就是每个串在自动机上跑一遍,记录每个节点的访问次数,为了避免重复,我们记录当前这个节点这个字符串走没走过,出现次数也是要向上推的。最后按照套路把贡献向上推,再
阅读全文
摘要:后缀自动机+dp 一个串在另一个串上跑。 先对A建出自动机,然后用B在上面跑,记录当前匹配的最大长度,每次经过一个节点记录经过次数,并加上(len-Max(par))*Right,是这个状态对答案的贡献,然后把每个节点的出现次数向par树上的祖先推一遍计算贡献。 #include<bits/stdc
阅读全文
摘要:后缀自动机+二分+倍增+线段树合并 后缀自动机真好用 后面一个串是固定的,那么我们要对前面的串进行一些操作。我们想既然是求lcp,那么我们得先翻转原串,这样前缀变成了后缀,然后二分一下,从d在自动机上的位置向上倍增,走到第一个Max大于当前答案的位置,用线段树合并判断一下当前是否满足。还是很好写的,
阅读全文
摘要:后缀自动机+dp 想了挺长时间 后缀自动机的状态图是一个dag,从root走到一个点的路径数代表了这个状态包含的子串,我们先预处理出来每个节点向后走能够形成多少子串,注意这里不是直接在parent树上求和,我们先求出每个节点的right集合的大小,然后在状态图上统计儿子的路径数,因为向儿子走相当于添
阅读全文
摘要:后缀自动机 辣鸡四平OJ 就是多串LCS,有点像AC自动机。先对一个串建立自动机,然后让其他串在上面跑。我们从根节点开始走,每次看儿子是否有这种字符,有的话直接向下走,步数+1,否则沿着par走,直到有为止。par的过程其实是不断缩短当前串来继续匹配。最后按parent树从叶子向上进行dp,每个点保
阅读全文
摘要:终于看懂了,写一点东西以防忘记,不保证讲的都对 1.什么是自动机?自动机是指对于一个自动机A,如果能识别字符串S,那么A(S)=true,否则A(S)=false,就像AC自动机能够识别给定文本中特定的文本一样。 1.5:后缀自动机和AC自动机一样,有两个比较重要的东西,AC自动机一般我们会碰到在自
阅读全文
摘要:ntt+cdq分治 原来zwh出的cf是斯特林 第二类斯特林数的定义是S(i,j)表示将i个物品分到j个无序集合的方案数,那么这道题中S(i,j)*j!*2^j是指将i个物品分到j个有序集合中并且每个集合可以选或不选的方案数,那么我们改变这个公式,得出 F[i]=∑F[j]*2*C(i,j),j=0
阅读全文
摘要:后缀自动机 留个板子 upd:大概懂了 每次新加入的npRight集合肯定只有最后一个位置,那么求所有长得不一样的子串贡献就是Max-Min+1,因为Right集合只有这一个位置,所以这Max-Min+1个子串只出现在最后一个位置。 #include<bits/stdc++.h> using nam
阅读全文
摘要:又是一年noip...再次炸裂 day0::发烧了,不知道该干些什么,打了几个板子,想了想常用的技巧,就睡觉了。 day1:看见第一题第一反应不会做,推了一会去做第二题,一个小时终于调对了,然后突然yy出了第一题的结论,此时还有两个小时,开第三题,思路比较明显,大概是个dp,但是似乎状态之间有环,于
阅读全文
摘要:树形dp 先拎出来一条直径,然后看直径上挂着的每条链,如果等于左边就把左端点放过来,等于右端点就把右端点放过来 #include<cstdio> #include<cstring> #include<algorithm> using namespace std; typedef long long
阅读全文
摘要:树形dp 很明显我们可以枚举一条边,然后求两边的重心,这样是暴力,我们用一些奇怪的方法来优化这个找重心的过程,我们先预处理出来每个点最大和第二的儿子,然后每次把断掉的子树的贡献减掉,每次找重心就是向最大或第二大的儿子走,如果最大的儿子被减掉后比第二大的儿子小或者这条边被剪掉了,那么就向第二大的儿子走
阅读全文
摘要:dp+树状数组 思维僵化怎么办。。。 我们都知道,如果两个序列中所有元素都不相同,那么可以用lis求解,复杂度nlogn,但是这道题不行,每种元素出现了5次。。。然后我一直在想有没有什么解决办法 事实上是这个样子的,考虑二维dp,dp[i][j]=dp[i-1][j-1]+1当且仅当s[i]==t[
阅读全文
摘要:题面:不存在的 我们先dfs一次,只保留每个分叉最上面的颜色,并求到根的前缀和,这就是每个点到根的和,记为s1,然后我们求子树里的,这里只保留了最上面的颜色,那么我们求树链的并,做树上前缀和,这就是子树颜色的和,记为s2,s1+s2就是子树和到根颜色的并,因为只保留了最上层的颜色,也就是说对于一个点
阅读全文
摘要:dp 字符串dp不太会啊。。。 这种序列和子串的匹配一般设两个状态,dp[i][j]表示当前s匹配到i,t匹配到j的...,g[i][j]表示当前s匹配到i,t匹配到j,i,j必须匹配的...,noip2015的子串也是这个套路,这道题是设最远能匹配到哪里,贪心显然,转移具体看代码,注意一定要把条件
阅读全文
摘要:二分+lca 我们把向中间缩看成向上爬,向两边走看成向下爬,那么就相当于找出两个状态的lca,如果相邻的差是(a,b),a<b,那么向中间走就是(a,b-a)或(b-a,a),这个东西很像更相减损术,那么我们直接用(b-1)/a算出来要走的步数,然后继续递归求lca,直到走不了为止。先爬inf步判断
阅读全文
摘要:贪心 n%3==1 分出一个4,其余用3,n%3==2,分出一个2,其余用3,然后高精度就行了 #include<bits/stdc++.h> using namespace std; const int N = 5005; struct BigInt { int len; int a[N]; Bi
阅读全文