摘要:
对于P*Q的矩形中每一个点挂一条长度为R的链,流量分别是下一个点的点权(链尾是inf),然后对于每一个点连向四周的后D个点连一条inf的边。 考虑最小割,当割掉某一条链的一条边,就表示选择该边,那么如果割掉的两条边相差大于D,那么一定可以顺着在前面的那个点走到另一条路上在走到汇点,不是满足条件的割。 阅读全文
摘要:
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define mod 1000000007 4 #define N 500005 5 #define ll long long 6 ll n,m,t,ans,mu[N],vis[N],p[N],c 阅读全文
摘要:
询问可以理解为将所有l~r的节点到根的路径都打上+1标记,然后询问相当于查询z到根的路径中有多少+1标记,这个问题可以转化为前缀和离线处理,用树链剖分套线段树维护。 还有一种分块的做法,对于每一个节点预处理出其到每一个块的答案,对于每一个块,可以发现f[k]=f[fa]+sz[k],其中sz[k]表 阅读全文
摘要:
离线读入并按照困难度排序,即相当于支持两种操作:连边和查询。对于每一个连通块在根节点建一个权值线段树,连边即合并两颗线段树,而查询就是在一棵线段树中查询(注意:边数和询问为$5*10^{5}$)。 1 #include<bits/stdc++.h> 2 using namespace std; 3 阅读全文
摘要:
暴力枚举两个数字并判定,如果不能同时选就连边,然后即求最大带权独立集。 普通图的最大带权独立集无法快速求出,但发现两个奇数一定无法使得1式成立(考虑模8,奇数平方模8为1,偶数平方模8为0或4),两个偶数一定无法使2式成立,因此奇数和偶数内部没有边,即形成了一张二分图。 首先假设所有数都可以选,考虑 阅读全文
摘要:
这道题有一种较为暴力的做法,对于每个点枚举所有与r2为该属性的询问并加以修改,最坏时间复杂度为o(nq),然而是可过的(97s) 发现只有当r2相同的询问数特别多时才会达到最坏时间复杂度,因此如果删除重复询问,时间复杂度降为o(nr),然而并没有显著优化(81s) 接着考虑当同一种r2的询问特别多时 阅读全文
摘要:
发现任意两个点的连边都是一棵从从叶子节点搜索出来的trie树的一段,那么可以对所有trie树建立一个广义后缀自动机即求该后缀自动机的字符串数量,同bzoj4516。 1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 100005 阅读全文
摘要:
首先计算出s数组,s表示可以重复的前缀等于后缀的个数,显然有s[i]=s[next[i]]+1,因为有且仅有next的next满足这个条件。 然后直接暴力枚举所有next,直到它小于i的一半,这个时间复杂度就是o(n)的 1 #include<bits/stdc++.h> 2 using names 阅读全文
摘要:
如果暴力dp的话时间复杂度为$o(n\sum_{i=1}^{n}ai)$,约为20亿。但显然我们对于f[i]只需要存储出现个数是奇数还是偶数就行了,即一个0/1。然后我们发现这只需要一个bitset就可以了,时间复杂度除以32,就可以过了。 1 #include<bits/stdc++.h> 2 u 阅读全文
摘要:
假设没有同时选文理科的收益,可以先将所有点的文理科收益都加起来,考虑最少要删掉多少收益,源点连向每一个点文科的收益,每一个点向汇点流理科的收益,然后每一条路径都最小割,即去掉了较小的收益。 但还有同时选同一种科目的收益,同样先加上所有选同种科目的收益,然后对于点(i,j),新增k1和k2两个点,源点 阅读全文
摘要:
首先将0变为-1,平衡的路径即该路径边权和为0,然后统计过重心且满足条件的路径数。 不断将统计当前这颗子树到之前所有子树的路径并合并,统计时,需要处理出两个桶a[i][j]和b[i][j],表示之前的子树/当前子树深度为i,到重心的路径中有(j=1)/没有(j=0)深度为0的节点(不能是根或本身)的 阅读全文
摘要:
这道题还有一种分块的做法:每当发现当前子树中有K个点,就将这K个点合在一起,然后把每个块内的节点权值排序(虽然这个算法并没有保证块的个数,但是由于数(shen)据(qi)随(hai)机(luo),所以不妨设为n/K)。 操作0:对于每一个块暴力查询(构建一颗虚树),然后对根所在块暴力,时间复杂度o( 阅读全文
摘要:
发现a是c的祖先,b是c的祖先,则a和b也一定是祖先关系。 a已经确定了,考虑b:1.若a是b的祖先,考虑a中每一个节点作为c的方案数,显然就是min(d[x]-d[a]-1,k),其中x!=a且在a的子树中;2.若b是a的祖先,很好处理,即min(d[a],k)*(sz[a]-1)(深度从0开始) 阅读全文
摘要:
建立后缀自动机,对于一个节点,根据len排序后依次统计(t为0时每一个点只有1的贡献,t为1时每个点有|right|的贡献)子树内的子串数量,然后不断确定字符即可。 1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 500005 阅读全文
摘要:
dfs序(注意出栈时也要加入),然后对于每一次一个节点的修改,都在左端点上打+x,右端点上打-x,区间修改同理(因此要用线段树且需要维护区间左端点数量-右端点数量)。对于询问操作,就是dfs序上的一段前缀和,用线段树处理即可。 1 #include<cstdio> 2 #include<cstrin 阅读全文
摘要:
1 #include<bits/stdc++.h> 2 #include<tr1/unordered_map> 3 using namespace std; 4 #define ll long long 5 #define N 5000005 6 int t,n,mu[N],vis[N],p[N]; 阅读全文
摘要:
每一个区间相当于对[x,n]新增一个p,对[y+1,n]减少一个p,那么建立一棵可持久化线段树,然后对于修改第p个位置,同时统计出子树的点数和所有的和,类似于二分确定即可。 1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 20 阅读全文
摘要:
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 50005 4 long long n,m,ans,mu[N],f[N],t[N],vis[N],p[N]; 5 void xxs(int n){ 6 mu[1]=f[1]=1; 阅读全文
摘要:
首先定义状态f[i][j]表示长度为i的串以j为结尾有多少符合条件的串,发现$f[i][j]=\sum f[i-1][k]$(j和k可以相邻),这个用矩阵乘法优化一下即可。 1 #include<bits/stdc++.h> 2 using namespace std; 3 #define ll l 阅读全文
摘要:
二分枚举答案,问题转化为计算至少取到一定体积,价格最少是多少,显然是贪心取最小,用线段树维护,然后因为要判断答案,所以可持久化一下即可。 1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 100005 4 #define mid 阅读全文
摘要:
维护两颗可持久化字典树(当然可以放在一起),第一棵维护每一个点到根的每一位的二进制数量,在其父亲的基础上建立;第二棵维护dfs序上每一个点到第1个点的二进制数量,在其上一个点的基础上建立。 对于询问1,在第二棵上询问该子树对应区间;对于询问2,拆成x~lca和lca~y两段询问,询问时直接贪心即可。 阅读全文
摘要:
首先考虑没有深度限制,即对一颗子树求颜色数,那么可以用树上差分,根据dfs序,每个点和这个颜色在dfs中上一次出现点的lca打-1,然后每个点再打上一个+1,然后求一颗子树内所有节点的标记和即为答案。 为了深度限制,因此可以以深度为时间建一棵可持久化线段树,然后查询(x,d)即查询第deep[x]+ 阅读全文
摘要:
建立后缀树(即反序插入字符串的parent树),然后可以发现按照dfs序排列满足其反串按字典序从小到大排列,那么就可以维护出每一刻子树的串长和,然后直接在dfs序上二分确定节点,再在节点内部乱搞即可求出答案。 1 #include<bits/stdc++.h> 2 using namespace s 阅读全文
摘要:
状态f[i][j][k][l]表示前i个数,四种数的最后一次出现的位置分别是i、j、k和l(i>j>k>l),判断所有第右端点为i的区间是否满足此要求(不满足重置为0),考虑第i+1个位置填什么,转移到下一个位置上即可。 这样的时间复杂度看似是$o(Tn^{4})$,实际上由于枚举只需要比上一个数小 阅读全文
摘要:
记可乐为1,汉堡为-1,即求过程中绝对值不超过k的最短路。 然后发现k的范围仅为10,也就是说过程中合法的值仅有21种,因此跑一遍dij或spfa(嘿嘿嘿)即可。 1 #include<bits/stdc++.h> 2 using namespace std; 3 #define pi pair<i 阅读全文