首先看两条链怎么合并,贪心可得是从大到小取max,多条链同理 所以dfs合并子树的大根堆即可,注意为了保证复杂度,合并的时候要合并到最长链上,证明见长链剖分 #include<iostream> #include<cstdio> #include<queue> using namespace std; const int N=200005; int n,a[N],h[N],cnt,id[N],tot,p[N]; long long ans; priority_queue…
题意 略 分析 稍微yy一下可以感觉就是一个不同子树合并堆,然后考场上写了一发左偏树,以为100分美滋滋.然而发现自己傻逼了,两个堆一一对应合并后剩下的一坨直接一次合并进去就行了.然鹅我这个sb把所有元素pop一次再merge进去-然后就O(n2)O(n^2)O(n2) 60分滚粗了- 啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊 时间复杂度分析: 每个点只会被pop出去一次,pop的时候伴随了一次pop一次merge. 每一对父子关系merge了一次 所以时间复杂度是O(nlogn)O(nlogn)…
[BZOJ5499][2019省队联测]春节十二响(贪心) 题面 BZOJ 洛谷 题解 如果是一条折链,显然维护两侧的值,每次两个堆分别弹出一个\(max\)然后合并一下,最后再放回去就可以了. 那么现在回到一棵树上,可以认为就是本身有一条链,现在每次要合并一条链进来,那么拿一个堆维护这个合并过程就可以了.为了保证复杂度用启发式合并. 在\(C++11\)下可以直接使用\(.swap()\)函数来进行优先队列的交换. 为了在\(BZOJ\)上过就写的普通的启发式合并. #include<cstd…
题目地址:P5290 [十二省联考2019]春节十二响 骗分方法 如果你实在一点思路也没有,暴力都不会打,那么请考虑一下骗分. 方法一 输出所有 \(M\) 的和. 期望得分:0分. 实际还有5分 方法二 注意到有 \(15\) 分为一条链,分两种情况考虑: 1号点有一个儿子--详见方法一. 1号点有两个儿子--把对这两个儿子下的两条链弄成两个堆,每次取出两个堆的堆顶,取 \(max\) 加入答案,当一个堆取尽后,把另一个堆里的所有元素加入答案,最后加入 \(M_1\) . 期望得分:15分.…
P5290 [十二省联考2019]春节十二响 从特殊到一般 我们先看链的情况. 我们把点$1$左右的两条子链分别扔入堆里 每次取出两个堆的最大值,把答案累加上更大的那个(另一堆为空则直接加上去). 那么......如果$1$连着多条链咋办? 我们又发现,你可以每次把每2条链所对的堆两两合并,并不影响答案. 那么......如果$1$连着多棵树咋办? 其实是链是树已经没多大区别了,因为它们之间互不影响. 于是做法就出来了 dfs把子树合并,一层层合并上去就好辣 注意为了保证复杂度$O(nlog^2…
这题果然是原题[BZOJ 3689 异或之].看了BZOJ原题题解,发现自己sb了,直接每个位置维护一个值保存找到了以这个位置为右端点的第几大,初始全部都是1,把每个位置作为右端点能够异或出来的最大值放入优先队列,然后找最大的一个累计答案后pop掉,假设找到的右端点是r,就把r能异或出来的第二大再加入队列.找k次就行了.这样在trie上找第k大就维护一个size就行了.mdzz这么显然居然没有想出来,还是自己太菜- 签到题没做来- CODE #include <bits/stdc++.h> u…
是个神仙dp-- 参考:https://www.luogu.org/blog/xzz-233/solution-p5289 设f[i][j][k]是前i个有限制的城市,所有学校中选蓝色阵营有j人,有限制的学校中鸭派系有k人的方案数:g[i][j]是前i个没有限制的城市,蓝色阵营有j人的方案数:h[i][j]是前i个没有限制的学校,鸭派系有j人的方案数 f的转移枚举当前阵营 全dp出来之后,把gh前缀和处理,然后一段一段的和f合并加到ans上 #include<iostream> #includ…
有一个想法就是暴力建图,把每个A向有和他相连的B前缀的A,然后拓扑一下,这样的图是n^2的: 考虑优化建图,因为大部分数据结构都是处理后缀的,所以把串反过来,题目中要求的前缀B就变成了后缀B 建立SAM,发现在parent树中每个B能走到的A都在子树中,所以保留这个树结构,连边权为0的边: 然后在parent树上倍增找到每个AB串对应的点,因为SAM上每个对应不止一个串,所以找完之后把对应多个AB串的点拆成一条链 然后对于一对(x,y)的AB串关系,Ax对应的点向By对应的点连边权为A长度的边…
和bzoj4504差不多,就是换了个数据结构 像超级钢琴一样把五元组放进大根堆,每次取一个出来拆开,(d,l,r,p,v)表示右端点为d,左端点区间为(l,r),最大区间和值为v左端点在p上 关于怎么快速求区间和,用一个可持久trie上维护最大xor值和对应的点即可 #include<iostream> #include<cstdio> #include<queue> //#include<ctime> using namespace std; const…
和超级钢琴,异或之三倍经验 $?$ 堆+贪心素质三连 $?$ 好无聊...... code: #include <bits/stdc++.h> #define N 500006 #define ll long long #define setIO(s) freopen(s".in","r",stdin) // , freopen(s".out","w",stdout) using namespace std; ch…