寒假刷题记录
2018.2.10更新 刷的题的题解慢慢补充
菜鸡趁着假期,搞了10天图论和数据结构
目前学习方法:从简单到困难一步步深入,看各路大神博客,看白书,理解思路,跟着敲多几遍模板题,
A多几题就背一下模板 刷题去vjudge搜kuangbin
WA点:数组开错,模板错误,数组初始化,scanf,行内空格,卡STL,long long
目前:图论新手,请多指教
图的表示方法:邻接表vector,邻接数组,前向星w
拓扑排序:
算法:队列实现,DFS实现,拓展:判有向图的环
刷题:POJ2367,hdu4324
图的最短路:
算法:Dij+heap,SPFA+queue/stack ,Floyd,(小图:DFS,BFS)
拓展:查分约束,次短路,第k短路(未学,需先修A*),判负环(SPFA),传递闭包(Floyd)
刷题:hdu1874 poj2387 poj2253 poj1797 poj3268 poj1860 poj3259 poj1502 poj3660
poj1511 poj3159 poj3255 hdu1142
并查集:
算法:DFS 拓展:路径压缩,求连通分量
刷题:
最小生成树:
算法:Kruskal(需先修并查集),Prim(未学)
拓展:最大生成树,次小生成树,第k小生成树(未学)
刷题:hdu1863 hdu1162 poj1215 hihocoder 1109 bzoj1821
//BZOJ1821 题意:给N<=1e3点坐标 任意分成K份 一种分法使得K份之间的最短距离最大 输出该最短距离
//思路:最小生成树,边从小到大排序,合并时计数(祖先一样说明同一连通分量,不要管),当ans=n-k时,此时已经分成k份,
//下一条最小生成树合并的边长度就是答案
//假设K=4,且A~D已经是最小生成树了,E F G 还是没边的点 假设下一条最小的边是BE,那么这条就是答案,因为不管是EF FG EG AG ...都比BE大
//选这些边就不满足最短距离最大了,因为AG不是最短距离,如果选AB BC这种 确实最最短距离,但是!不是最大的最短距离
//Kruskal遍历边时每次都会尝试选一个最短边的俩端点合并到同一连通分支,最后只会剩一个连通分支,否则返回-1
树上最近公共祖先LCA:
算法:倍增+DFS(二进制逼近),ST表+RMQ+DFS(重要,且好学)
Tarjan(离线,需先修并查集)
拓展:树上两点最短距离(查询多)
刷题:POJ1330 hdu2586 CF832D (每种都A一遍)
线段树:(目前14道)
算法:数组实现,向下更新儿砸推lazy,向上更新儿砸向上更新父亲
维护满足区间加法的快速区间查询,区间修改
注意:4倍空间,多标记的处理,有什么操作?单点代表什么信息?区间维护什么信息?满足区间加法吗?
(题量不足)
刷题://hdu1754点更+查 区间信息:最大值 点信息:int 修改:=a 1076ms
//hdu1698区更+查 区间信息:加法和 点信息:int 修改:=a 1014ms
//hdu1166点更+查 区间信息:加法和 点信息:int 修改:+=a 608ms
//hdu1556区更+查 区间信息:出现次数和 点信息:覆盖次数 修改:+=1 1263ms
//POJ2777区更(替换颜色)+查颜色状态 区间信息:区间内颜色状态 点信息:一种颜色状态 修改:替换颜色 391ms
//查到区间内颜色状态就可以 用1位1位导出有多少种颜色了 状态压缩颜色种类<30种颜色
//BZOJ1012 插入+查 m个操作 那么最多插入m个元素,每次build不刷新val,找到叶子节点后更新值,每次递归需要向上更新
//区间信息:最大值 920ms 点信息:值 ,cnt=2 1,6 -> 1,3√ 4,6 1,3-> 1,2√ 3 2,2√ 更新val,pushup上面的1,3 1,2
//BZOJ3038 查询区间和,区间修改:(int)sqrt(a) 维护区间和,暴力修改叶子,剪枝:维护最大值,最大值>=1才递归下去
//落谷 查询区间和 区间修改 1,x=a 2,+=a 双标记 ,维护sum lazy1:mul lazy2:add mul标记初始化是1 注意取模,开 longlong
//POJ3468 检验板子的时候到了
hdu1166again 866ms
hdu1754again 964ms
poj3468again 2614ms(G++) 1750ms(C++)
//hdu2528 修改:颜色覆盖,查询整段区间颜色数 +离散化,query不太会 区间维护col 离散化技巧get
//hdu1698again 939ms
//ZOJ1610: 8000条线段的线段树,N次修改,区间修改l r c ,l r是点,c的修改的颜色下标 0<=l<=8000 c++,30ms
//一般对线段进行建树,所以左端点加1即可 ,
//区间信息(非leaf):区间的颜色,比如某个节点表示【1,4】的值可能是3:即线段【1,4】都是颜色3
//注意:这个值要么是-1要么区间内都是一种颜色,如果这时候我输入3 4 2,此时区间【1,4】内有多种颜色,update会先递归root【1,4】
// 由于有pushdown的力量,【1,2】=3,【3,4】=3,【1,4】=-1 ,然后update递归到root【3,4】时 将【3,4】置于2;
//这样就能lazy动态区间修改并维护 区间内的颜色分布了!(没有颜色也是颜色)
//最后一次性pushdown所有lazy标记到叶子 ,暴力查询到叶子 tem数组记录出现次数
//POJ3264 区间查询2e5 最大最小值的差 分别维护最大值,最小值即可 2219ms
//hdu4027 区间修改:区间内所有数开根号下取整,区间查询:加法和
//思路:维护sum 暴力修改叶子,回溯时pushup修改其他非叶子节点,
//剪枝:修改时若当前sum为numr-numl+1(每个数都是1)且当前区间是修改区间的子区间,那么可以不递归下去
//或者多维护一个区间最大值mx,最大值为1的时候就不递归下去
//CF920F 线段树 区间查询和,区间修改ai变d(ai) d(x)返回x的因子数
//思路:d(2)=2 d(1)=1; update暴力修改叶子,update剪枝即可
//小心:long long 不能用sum<=2*(numr-numl+1)剪枝hack: 1 3
//所以维护多一个区间最大值mx,来剪,mx<=2即可剪枝
树链剖分:
算法:DFS DFS (树序哈希成线性序)+线段树(目前只会这个= =)
刷题:SPOJ-QTREE bzoj4034
//SPOJ-QTREE 190ms (对边操作)
//题意: 给一颗树n<=10000 若干查询 点l到点r的路径的最长边的长度 若干修改:
//按输入序第i条边的值修改为c;
//
//轻重链剖分 裸题 两遍DFS +线段树维护区间最大值+区间单点更新
//
//概念:点u的重儿砸v:子树数目最多的儿砸v 重边:u->v 重链:重边连成的路径
//fa[u]:点u的爸爸,siz[u]点u的子树数目(包括自己) son[u]重链的儿砸
//这题修改是通过输入序的边下标修改边权值,所以建边表+邻接表比较合理 前向星倒序输入反而不好处理
//当然,不同题目不同建图
//树剖其实就是将树节点序列 转为 同一重链连续 的 序列
//通过id[i]将图论域的点下标转换为线段树域的下标
//第一个DFS 维护 fa,dep,son,siz(跟倍增LCA的第一个DFS思路一致)
//第二个DFS 维护 top id (需要用到son) 利用 top[u]=top[son[u]] (轻链的top就是自己)
// 2个DFS均是对当前点u的邻接点进行遍历
//build query updateone 是线段树常规操作
//light(u,v) 是核心查询: 代码思路:第一步:将u v转至同一重链:u转top 并fa之,
//转top来到重链首,fa之跳到下一条重链尾
//u v但不可同时转top fa之,可能会错过,一般是深度大的u转top fa之
//过程中需要不断维护ans,线段树查询u所在的整条重链的最大值
//第二步:此时已经在同一重链了,就可以直接线段树查询了
//记住:深度小的图论下标对应的线段树下标较小
//且点x的子树x1x2x3...xn 对应的线段树下标是连续的 x->y x2->y+1 x8->y+2...(由于DFS序,同样满足重链连续)
//其实这题是对边操作,强行将其转为对点操作 ,那么规定
//深度大的点u 指向 深度小的点v 的边权值 看成u的权值
//比如输入的u(下标1,深度大)->v(下标2,深度小) 边uv=3 那么将u的权值定为3
//
//ans=max(ans,query(1,num,id[son[u]],id[v],1));
//这也是为什么light第二步同一重链的查询是id[son[u]]到id[v]了
//这样不会乱!
//另外,这题有行中多空格,s数组开大点就不会RE了
搜索:
算法:DFS BFS
刷题:POJ1321 POJ2251 计蒜客20695 hiho1191判断二分图
其他:
hdu1263 二维map
POJ1064 小数二分
hdu5778 简单数论
hdu1848 SG函数博弈模板题
hdu2582 规律+线性筛预处理最小质因子
POJ3104 思维+整数二分
小技巧:
1:离散化:数的映射,缩小范围,0 3 5 66->1 2 3 4
思路:排序后遍历去重(必要时还可以尾部插入中间值然后再排序一次)
二分lowerbound找出离散化后的新坐标
int getrk2(int x) { return lower_bound(rk+1,rk+1+rn,x)-rk;}
题目:hdu2528
2:原数组元素顺序不能变,但是需要求某种元素顺序得到的最大ans
思路:建一个辅助数组初始化id[i]=i(这个i是原数组下标),
对id数组进行某种优先级排序后,用id[i]得到原数组的下标进行计算
比如:排序后id[]={2,3,4,1}那么优先级最大的原数组下标就是id[1]=2
题目:CF922D