浙江大学_acm程序设计竞赛_培训_线段树
acm程序设计 线段树和间断树
Segment trees and interval treesLecture5Antoine Vigneronantoine.vigneron@jouy.inra.frINRAOutline referencetextbook chapter10D.Mount Lectures13and24segment trees⇒stabbing queries⇒rectangle intersection interval trees⇒improvementhigher dimensionStabbing queries orthogonal range searching:data points,queryrectanglestabbing problem:data rectangles,query pointin one dimensioninput:a set of n intervals,a query point qoutput:the k intervals that contain qin I R da boxb is isothetic iff it can be writtenb=[x1,x 1]×[x2,x 2]×...×[x d,x d]in other words it is axis–parallelinput:a set of n isothetic boxes,a query point qoutput:the k boxes that contain qMotivationin graphics and databases,objects are often stored intheir bounding boxquery:which objects does point x belong to?firstfind objects whose bounding boxes intersect xSegment treesSegmenttreea data structure to store intervals,or segments in I R2allows to answer stabbingqueriesin I R 2:report the segments that intersect a query vertical line lreportedreportedreportedlquery time:O (log n +k)space usage:O (n log n)preprocessing time:O (n log n )Notationslet S=(s1,s2,...s n)be a set of segments in I R2let E be the set of the x–coordinates of the endpoints ofthe segments of Swe assume general position,that is:|E|=2nfirst sort E in increasing orderE={e1<e2<...e2n}AtomicintervalsE splits I R into2n+1atomicintervals:[−∞,e1][e i,e i+1]for i∈{1,2,...2n−1}[e2n,∞]these are the leaves of the segmenttreeInternalnodesthe segment tree T is a balanced binarytree each internal node u with children v and v is associatedwith an interval I u =I v ∪Iv an elementary interval is an interval associated with a node of T (it can be an atomicinterval)I v I vExamplePartitioning asegmentlet s∈S be a segment whose endpoints havex–coordinates e i and ej[e i,e j]is split into several elementaryintervalsthey are chosen as close as possible to theroots is stored in each node associated with these elementaryintervalsStandard listseach node u is associated with a standard list L ulet e i<e j be the x–coordinates of the endpoints of s∈Sthen s is stored in L u iff I u⊂[e i,e j]andI parent(u)⊂[e i,e j](see previous slide and next slide)ExampleAlgorithm ReportStabbing(u,x l) Input:root u of T,x–coordinate of l Output:segments in S that cross l1.if u==NULL2.then return3.output L u4.if x l∈I u.left5.then ReportStabbing(u.left,x l)6.if x l∈I u.right7.then ReportStabbing(u.right,x l)it clearly takes O(k+log n)timeInserting asegmentInsertion in a segment tree Algorithm Insert(u,s)Input:root u of T,segment s.Endpoints of s have x–coordinates x−<x+1.if I u⊂[x−,x+]2.then insert s into L u3.else4.if[x−,x+]∩I u.left=∅5.then Insert(u.left,s)6.if[x−,x+]∩I u.right=∅7.then Insert(u.right,s)Propertys is stored at most twice at each level ofTproof:bycontradictionif s stored at more than2nodes at leveli let u be the leftmost such node,u be therightmost let v be another node at level i containingsu v uv.parentthen I v.parent⊂[x−,x+]so s cannot be stored at vAnalysisproperty of previous slide impliesspace usage:O(n log n)insertion in O(log n)time(similar proof:four nodes atmost are visited at each level)actually space usage isΘ(n log n)(example?)query time:O(k+log n)preprocessingsort endpoints:Θ(n log n)timebuild empty segment tree over these endpoints:O(n)timeinsert n segments into T:O(n log n)timeoverall:Θ(n log n)preprocessing timeRectangle intersectionProblem statementinput:a set B of n isothetic boxes in I R2output:all the intersecting pairs in B2using segment trees,we give an O(n log n+k)timealgorithm when k is the number of intersecting pairs note:this is optimalnote:faster than our line segment intersection algorithmspace usage:Θ(n log n)due to segment treesspace usage is not optimal(O(n)is possible withoptimal query time and preprocessing time)Exampleb 2b 5output:(b 1,b 3),(b 2,b 3),(b 2,b 4),(b 3,b 4)Two kinds ofintersectionsoverlapintersecting edges⇒reduces to intersectionreporting for isotheticsegmentsinclusion we can find them using stabbing queriesReporting overlapsequivalent to reporting intersecting edgesplane sweep approachsweep line status:BBST containing the horizontal linesegments that intersect the sweep line,by increasingy–coordinateseach time a vertical line segment is encountered,reportintersection by range searching in the BBST preprocessing time:O(n log n)for sorting endpointsrunning time:O(k+n log n)Reporting inclusionsstill using plane sweepsweep line status:the boxes that intersect the sweepline l,in a segment tree with respect to y–coordinates the endpoints are the y–coordinates of the horizontaledges of the boxesat a given time,only rectangles that intersect l are inthe segment treewe can perform insertion and deletions in a segmenttree in O(log n)timeeach time a vertex of a box is encountered,perform astabbing query in the segment treeRemarksat each step a box intersection can be reported severaltimesin addition there can be overlap and vertex stabbing abox at the same timeto obtain each intersecting pair only once,make somesimple checks(how?)Interval treesIntroductioninterval trees allow to perform stabbing queries in onedimensionquery time:O(k+log n)preprocessing time:O(n log n)space:O(n)reference:D.Mount notes,page100(vertical linestabbing queries)to page103(not including vertical segment stabbing queries)Preliminarylet x med be the median ofES l:segments of S that are completely to the left of xmedS med:segments of S that contain xmedS r:segments of S that are completely to the right of x medx medS medS rS lData structurerecursive data structureleft child of the root:interval tree storing S lright child of the root:interval tree storing S rat the root of the interval tree,we store S med in two listsM L is sorted according to the coordinate of the leftendpoint(in increasing order)M R is sorted according to the coordinate of the rightendpoint(in decreasing order)Examples 1s 2s 3s 5s 7s 4s 6Interval tree ons 3and s 5Interval tree on M l =(s 4,s 6,s 1)M r =(s 1,s 4,s 6)s 2and s 7Stabbing queriesquery:x q,find the intervals that contain x qif x q<x med thenScan M l in increasing order,and report segmentsthat are stabbed.When x q becomes smaller than the x–coordinate of the current left endpoint,stop.recurse on S lif x q>x medanalogous,but on the right sideAnalysisquery timesize of the subtree divided by at least two at eachlevelscanning through M l or M r:proportional to thenumber of reported intervalsconclusion:O(k+log n)timespace usage:O(n)(each segment is stored in two lists,and the tree is balanced)preprocessing time:easy to do it in O(n log n)timeStabbing queries in higherdimensionApproachin I R d,a set B of n boxesfor a query point qfind all the boxes that contain itwe use a multi–level segment treeinductive definition,induction on dfirst,we store B in a segment tree T with respect tox1–coordinatefor all node u of T,associate a(d−1)–dimensionalmulti–level segment tree over L u,with respect to (x2,x3...x d)Performing queriessearch for q in Tfor all nodes in the search path,query recursively the(d−1)–dimensional multi–level segment treethere are log n such queriesby induction on d,we can prove thatquery time:O(k+log d n)space usage:O(n log d n)preprocessing time:O(n log d n)Improvementsfractional cascading at the deepest level of the tree:gains a factor log n on the query time boundinterval trees at the deepest level:gains log n on the space bound。
线段树以及数组数组类型各题总结-acm
线段树之hdu4027Can you answer these queries?Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 65768/65768 K (Java/Others)Total Submission(s): 4014 Accepted Submission(s): 979Problem DescriptionA lot of battleships of evil are arranged in a line before the battle. Our commander decides to use our secret weapon to eliminate the battleships. Each of the battleships can be marked a value of endurance. For every attack of our secret weapon, it could decrease the endurance of a consecutive part of battleships by make their endurance to the square root of it original value of endurance. During the series of attack of our secret weapon, the commander wants to evaluate the effect of the weapon, so he asks you for help.Y ou are asked to answer the queries that the sum of the endurance of a consecutive part of the battleship line.Notice that the square root operation should be rounded down to integer.InputThe input contains several test cases, terminated by EOF.For each test case, the first line contains a single integer N, denoting there are N battleships of evil in a line. (1 <= N <= 100000)The second line contains N integers Ei, indicating the endurance value of each battleship from the beginning of the line to the end. Y ou can assume that the sum of all endurance value is less than 263.The next line contains an integer M, denoting the number of actions and queries. (1 <= M <= 100000)For the following M lines, each line contains three integers T, X and Y. The T=0 denoting the action of the secret weapon, which will decrease the endurance value of the battleships between the X-th and Y-th battleship, inclusive. The T=1 denoting the query of the commander which ask for the sum of the endurance value of the battleship between X-th and Y-th, inclusive.OutputFor each test case, print the case number at the first line. Then print one line for each query. And remember follow a blank line after each test case.Sample Input101 2 3 4 5 6 7 8 9 1050 1 101 1 101 1 50 5 81 4 8Sample OutputCase #1:1976Source/*一个10^5的序列,有10^5个操作,每个操作为a,b,ca=0时将b到c区间内的数都开根号下取整,a=1时求b到c段的和其中所有数的和不超过2^63。
线段树
线段树目录定义基本结构实现代码树状数组编辑本段定义区间在[1,5]内的线段树线段树又称区间树,是一种对动态集合进行维护的二叉搜索树,该集合中的每个元素 x 都包含一个区间 Interval [ x ]。
线段树支持下列操作:Insert(t,x):将包含区间 int 的元素 x 插入到树中;Delete(t,x):从线段树 t 中删除元素 x;Search(t,i):返回一个指向树 t 中元素 x 的指针。
编辑本段基本结构线段树是建立在线段的基础上,每个结点都代表了一条线段[a , b]。
长度为1的线段称为元线段。
非元线段都有两个子结点,左结点代表的线段为[a , (a + b ) / 2],右结点代表的线段为[( a + b ) / 2 , b]。
右图就是一棵长度范围为[1 , 5]的线段树。
长度范围为[1 , L] 的一棵线段树的深度为log ( L - 1 ) + 1。
这个显然,而且存储一棵线段树的空间复杂度为O(L)。
线段树支持最基本的操作为插入和删除一条线段。
下面以插入为例,详细叙述,删除类似。
将一条线段[a , b] 插入到代表线段[l , r]的结点p中,如果p不是元线段,那么令mid=(l+r)/2。
如果b<mid,那么将线段[a , b] 也插入到p的左儿子结点中,如果a>mid,那么将线段[a , b] 也插入到p的右儿子结点中。
插入(删除)操作的时间复杂度为O (Log N)。
上面的都是些基本的线段树结构,但只有这些并不能做什么,就好比一个程序有输入没输出,根本没有任何用处。
最简单的应用就是记录线段有否被覆盖,并随时查询当前被覆盖线段的总长度。
那么此时可以在结点结构中加入一个变量int count;代表当前结点代表的子树中被覆盖的线段长度和。
这样就要在插入(删除)当中维护这个count值,于是当前的覆盖总值就是根节点的count值了。
另外也可以将count换成bool cover;支持查找一个结点或线段是否被覆盖。
【综合】Acm竞赛简介
Parity(ceoi99)(肖天)
• 建立sum数组,sum[i]表示从1到i之和是奇(true)还是偶 (false),sum[0]=false。这样题目中给的任意问题(a,b) 的答案都可以用sum[b] xor sum[a-1]表示。 • 开始我们并不知道sum[1..n]的值,不妨设为false,这时任意 sum[a],sum[b]都是独立的。对于每对问答(a,b,c),都可以 知道sum[b] xor sum[a-1]=c,由此把sum[b]和sum[a-1] 联系起来。这步操作可以用并查集完成,对于问答(a,b,c)如 果sum[a-1],sum[b]不属于一个集合就把它们并起来,否则 如果sum[a-1] xor sum[b]不等于c则说明出现矛盾,输出总 句数,退出。 • 对于不出现矛盾的sum数组,对于每个集合分为两个部分,我 们指定其中一个部分为true,另一个部分为false,则可以确定 sum数组,利用sum[i] xor sum[i-1]可以求出第i位的数字, 由于不同集合之间没有问答出现,所以此数列是一可行解,证 明算法正确。
• 但有时却是最好的办法
22
Pizza Anyone? (ZOJ 1219)
• 题目大意: 你需要为你和你的朋友们订一个皮萨。 每个朋友都会告诉你他们想和不想放进皮萨 里的东西。 你是否能订一个皮萨,让他满足每个人 至少一个条件。 假设一共有16种东西可以放进皮萨。
23
2 65536
16
是个对计算机很 小的数
3
ACM
ACM (Association for Computing Machinery) 成立于计算机诞生次年,是目前计算机学界中历史最 悠久、最具权威性的组织,是推进信息技术专业人员 和学生提高技巧的主要力量。ACM通过提供前沿技 术信息和从理论到实践的转化,为其全球7.5万名成 员服务,并已经成为信息科技领域的一个基本信息来 源。
acm训练资料(浙大模板)
1、几何1.1 注意 (4)1.2 几何公式 (4)1.3 多边形 (6)1.4 多边形切割 (9)1.5 浮点函数 (10)1.6 面积 (15)1.7 球面 (16)1.8 三角形 (17)1.9 三维几何 (19)1.10 凸包 (26)1.11 网格 (28)1.12 圆 (29)1.13 整数函数 (30)2、组合2.1 组合公式 (33)2.2 排列组合生成 (33)2.3 生成gray码 (35)2.4 置换(polya) (35)2.5 字典序全排列 (36)2.6 字典序组合 (36)3、结构3.1 并查集 (37)3.2 堆 (38)3.3 线段树 (39)3.4 子段和 (44)3.5 子阵和 (44)4、数论4.1 阶乘最后非0位 (45)4.2 模线性方程组 (46)4.3 素数 (47)4.4 欧拉函数 (48)5、数值计算5.1 定积分计算(Romberg) (49)5.2 多项式求根(牛顿法) (51)5.3 周期性方程(追赶法) (52)6、图论—NP搜索6.1 最大团 (53)6.2 最大团(n<64)(faster) (54)7、图论—连通性7.1 无向图关键点(dfs邻接阵) (56)7.2 无向图关键边(dfs邻接阵) (57)7.3 无向图的块(bfs邻接阵) (58)7.4 无向图连通分支(dfs/bfs邻接阵) (59)7.5 有向图强连通分支(dfs/bfs邻接阵) (60)7.6 有向图最小点基(邻接阵) (61)8、图论—匹配8.1 二分图最大匹配(hungary邻接表) (62)8.2 二分图最大匹配(hungary邻接阵) (63)8.3 二分图最大匹配(hungary正向表) (63)8.4二分图最佳匹配(kuhn_munkras邻接阵) (64)8.5 一般图匹配(邻接表) (65)8.6 一般图匹配(邻接阵) (66)8.7 一般图匹配(正向表) (66)9、图论—网络流9.1 最大流(邻接阵) (67)9.2 上下界最大流(邻接阵) (68)9.3 上下界最小流(邻接阵) (69)9.4 最大流无流量(邻接阵) (70)9.5 最小费用最大流(邻接阵) (70)10、图论—应用10.1 欧拉回路(邻接阵) (71)10.2 树的前序表转化 (72)10.3 树的优化算法 (73)10.4 拓扑排序(邻接阵) (74)10.5 最佳边割集 (75)10.6 最佳点割集 (76)10.7 最小边割集 (77)10.8 最小点割集 (78)10.9 最小路径覆盖 (80)11、图论—支撑树11.1 最小生成树(kruskal邻接表) (80)11.2 最小生成树(kruskal正向表) (82)11.3 最小生成树(prim+binary_heap邻接表) (83)11.4 最小生成树(prim+binary_heap正向表) (84)11.5 最小生成树(prim+mapped_heap邻接表) (85)11.6 最小生成树(prim+mapped_heap正向表) (87)11.7 最小生成树(prim邻接阵) (88)11.8 最小树形图(邻接阵) (88)12、图论—最短路径12.1 最短路径(单源bellman_ford邻接阵) (90)12.2 最短路径(单源dijkstra+bfs邻接表) (90)12.3 最短路径(单源dijkstra+bfs正向表) (91)12.4 最短路径(单源dijkstra+binary_heap邻接表) (92)12.5 最短路径(单源dijkstra+binary_heap正向表) (93)12.6 最短路径(单源dijkstra+mapped_heap邻接表) (94)12.7 最短路径(单源dijkstra+mapped_heap正向表) (95)12.8 最短路径(单源dijkstra邻接阵) (96)12.9 最短路径(多源floyd_warshall邻接阵) (97)13、应用13.1 Joseph问题 (97)13.2 N皇后构造解 (98)13.3 布尔母函数 (99)13.4 第k元素 (99)13.5 幻方构造 (100)13.6 模式匹配(kmp) (101)13.7 逆序对数 (102)13.8 字符串最小表示 (102)13.9 最长公共单调子序列 (103)13.10 最长子序列 (104)13.11 最大子串匹配 (105)13.12 最大子段和 (106)13.13 最大子阵和 (106)14、其它14.1 大数(只能处理正数) (107)14.2 分数 (113)14.3 矩阵 (115)14.4 线性方程组 (117)14.5 线性相关 (119)14.6 日期 (120)1、几何1.1注意1. 注意舍入方式(0.5的舍入方向);防止输出-0.2. 几何题注意多测试不对称数据.3. 整数几何注意xmult和dmult是否会出界;符点几何注意eps的使用.4. 避免使用斜率;注意除数是否会为0.5. 公式一定要化简后再代入.6. 判断同一个2*PI域内两角度差应该是abs(a1-a2)<beta||abs(a1-a2)>pi+pi-beta;相等应该是abs(a1-a2)<eps||abs(a1-a2)>pi+pi-eps;7. 需要的话尽量使用atan2,注意:atan2(0,0)=0,atan2(1,0)=pi/2,atan2(-1,0)=-pi/2,atan2(0,1)=0,atan2(0,-1)=pi.8. cross product = |u|*|v|*sin(a)dot product = |u|*|v|*cos(a)9. (P1-P0)x(P2-P0)结果的意义:正: <P0,P1>在<P0,P2>顺时针(0,pi)内负: <P0,P1>在<P0,P2>逆时针(0,pi)内0 : <P0,P1>,<P0,P2>共线,夹角为0或pi10. 误差限缺省使用1e-8!1.2几何公式三角形:1. 半周长P=(a+b+c)/22. 面积S=aHa/2=absin(C)/2=sqrt(P(P-a)(P-b)(P-c))3. 中线Ma=sqrt(2(b^2+c^2)-a^2)/2=sqrt(b^2+c^2+2bccos(A))/24. 角平分线Ta=sqrt(bc((b+c)^2-a^2))/(b+c)=2bccos(A/2)/(b+c)5. 高线Ha=bsin(C)=csin(B)=sqrt(b^2-((a^2+b^2-c^2)/(2a))^2)6. 内切圆半径r=S/P=asin(B/2)sin(C/2)/sin((B+C)/2)=4Rsin(A/2)sin(B/2)sin(C/2)=sqrt((P-a)(P-b)(P-c)/P)=Ptan(A/2)tan(B/2)tan(C/2)7. 外接圆半径R=abc/(4S)=a/(2sin(A))=b/(2sin(B))=c/(2sin(C))四边形:D1,D2为对角线,M对角线中点连线,A为对角线夹角1. a^2+b^2+c^2+d^2=D1^2+D2^2+4M^22. S=D1D2sin(A)/2(以下对圆的内接四边形)3. ac+bd=D1D24. S=sqrt((P-a)(P-b)(P-c)(P-d)),P为半周长正n边形:R为外接圆半径,r为内切圆半径1. 中心角A=2PI/n2. 内角C=(n-2)PI/n3. 边长a=2sqrt(R^2-r^2)=2Rsin(A/2)=2rtan(A/2)4. 面积S=nar/2=nr^2tan(A/2)=nR^2sin(A)/2=na^2/(4tan(A/2))圆:1. 弧长l=rA2. 弦长a=2sqrt(2hr-h^2)=2rsin(A/2)3. 弓形高h=r-sqrt(r^2-a^2/4)=r(1-cos(A/2))=atan(A/4)/24. 扇形面积S1=rl/2=r^2A/25. 弓形面积S2=(rl-a(r-h))/2=r^2(A-sin(A))/2棱柱:1. 体积V=Ah,A为底面积,h为高2. 侧面积S=lp,l为棱长,p为直截面周长3. 全面积T=S+2A棱锥:1. 体积V=Ah/3,A为底面积,h为高(以下对正棱锥)2. 侧面积S=lp/2,l为斜高,p为底面周长3. 全面积T=S+A棱台:1. 体积V=(A1+A2+sqrt(A1A2))h/3,A1.A2为上下底面积,h为高(以下为正棱台)2. 侧面积S=(p1+p2)l/2,p1.p2为上下底面周长,l为斜高3. 全面积T=S+A1+A2圆柱:1. 侧面积S=2PIrh2. 全面积T=2PIr(h+r)3. 体积V=PIr^2h圆锥:1. 母线l=sqrt(h^2+r^2)2. 侧面积S=PIrl3. 全面积T=PIr(l+r)4. 体积V=PIr^2h/3圆台:1. 母线l=sqrt(h^2+(r1-r2)^2)2. 侧面积S=PI(r1+r2)l3. 全面积T=PIr1(l+r1)+PIr2(l+r2)4. 体积V=PI(r1^2+r2^2+r1r2)h/3球:1. 全面积T=4PIr^22. 体积V=4PIr^3/3球台:1. 侧面积S=2PIrh2. 全面积T=PI(2rh+r1^2+r2^2)3. 体积V=PIh(3(r1^2+r2^2)+h^2)/6球扇形:1. 全面积T=PIr(2h+r0),h为球冠高,r0为球冠底面半径2. 体积V=2PIr^2h/31.3多边形#include <stdlib.h>#include <math.h>#define MAXN 1000#define offset 10000#define eps 1e-8#define zero(x) (((x)>0?(x):-(x))<eps)#define _sign(x) ((x)>eps?1:((x)<-eps?2:0))struct point{double x,y;};struct line{point a,b;};double xmult(point p1,point p2,point p0){return (p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y);}//判定凸多边形,顶点按顺时针或逆时针给出,允许相邻边共线int is_convex(int n,point* p){int i,s[3]={1,1,1};for (i=0;i<n&&s[1]|s[2];i++)s[_sign(xmult(p[(i+1)%n],p[(i+2)%n],p[i]))]=0;return s[1]|s[2];}//判定凸多边形,顶点按顺时针或逆时针给出,不允许相邻边共线int is_convex_v2(int n,point* p){int i,s[3]={1,1,1};for (i=0;i<n&&s[0]&&s[1]|s[2];i++)s[_sign(xmult(p[(i+1)%n],p[(i+2)%n],p[i]))]=0;return s[0]&&s[1]|s[2];}//判点在凸多边形内或多边形边上,顶点按顺时针或逆时针给出int inside_convex(point q,int n,point* p){int i,s[3]={1,1,1};for (i=0;i<n&&s[1]|s[2];i++)s[_sign(xmult(p[(i+1)%n],q,p[i]))]=0;return s[1]|s[2];}//判点在凸多边形内,顶点按顺时针或逆时针给出,在多边形边上返回0int inside_convex_v2(point q,int n,point* p){int i,s[3]={1,1,1};for (i=0;i<n&&s[0]&&s[1]|s[2];i++)s[_sign(xmult(p[(i+1)%n],q,p[i]))]=0;return s[0]&&s[1]|s[2];}//判点在任意多边形内,顶点按顺时针或逆时针给出//on_edge表示点在多边形边上时的返回值,offset为多边形坐标上限int inside_polygon(point q,int n,point* p,int on_edge=1){point q2;int i=0,count;while (i<n)for (count=i=0,q2.x=rand()+offset,q2.y=rand()+offset;i<n;i++)if(zero(xmult(q,p[i],p[(i+1)%n]))&&(p[i].x-q.x)*(p[(i+1)%n].x-q.x)<eps&&(p[i].y-q.y)*(p[(i+1)% n].y-q.y)<eps)return on_edge;else if (zero(xmult(q,q2,p[i])))break;else if (xmult(q,p[i],q2)*xmult(q,p[(i+1)%n],q2)<-eps&&xmult(p[i],q,p[(i+1)%n])*xmult(p[i],q2,p[(i+1) %n])<-eps)count++;return count&1;}inline int opposite_side(point p1,point p2,point l1,point l2){return xmult(l1,p1,l2)*xmult(l1,p2,l2)<-eps;}inline int dot_online_in(point p,point l1,point l2){return zero(xmult(p,l1,l2))&&(l1.x-p.x)*(l2.x-p.x)<eps&&(l1.y-p.y)*(l2.y-p.y)<eps;}//判线段在任意多边形内,顶点按顺时针或逆时针给出,与边界相交返回1int inside_polygon(point l1,point l2,int n,point* p){point t[MAXN],tt;int i,j,k=0;if (!inside_polygon(l1,n,p)||!inside_polygon(l2,n,p))return 0;for (i=0;i<n;i++)if (opposite_side(l1,l2,p[i],p[(i+1)%n])&&opposite_side(p[i],p[(i+1)%n],l1,l2)) return 0;else if (dot_online_in(l1,p[i],p[(i+1)%n]))t[k++]=l1;else if (dot_online_in(l2,p[i],p[(i+1)%n]))t[k++]=l2;else if (dot_online_in(p[i],l1,l2))t[k++]=p[i];for (i=0;i<k;i++)for (j=i+1;j<k;j++){tt.x=(t[i].x+t[j].x)/2;tt.y=(t[i].y+t[j].y)/2;if (!inside_polygon(tt,n,p))return 0;}return 1;}point intersection(line u,line v){point ret=u.a;double t=((u.a.x-v.a.x)*(v.a.y-v.b.y)-(u.a.y-v.a.y)*(v.a.x-v.b.x)) /((u.a.x-u.b.x)*(v.a.y-v.b.y)-(u.a.y-u.b.y)*(v.a.x-v.b.x));ret.x+=(u.b.x-u.a.x)*t;ret.y+=(u.b.y-u.a.y)*t;return ret;}point barycenter(point a,point b,point c){line u,v;u.a.x=(a.x+b.x)/2;u.a.y=(a.y+b.y)/2;u.b=c;v.a.x=(a.x+c.x)/2;v.a.y=(a.y+c.y)/2;v.b=b;return intersection(u,v);}//多边形重心point barycenter(int n,point* p){point ret,t;double t1=0,t2;int i;ret.x=ret.y=0;for (i=1;i<n-1;i++)if (fabs(t2=xmult(p[0],p[i],p[i+1]))>eps){t=barycenter(p[0],p[i],p[i+1]);ret.x+=t.x*t2;ret.y+=t.y*t2;t1+=t2;}if (fabs(t1)>eps)ret.x/=t1,ret.y/=t1;return ret;}1.4多边形切割//多边形切割//可用于半平面交#define MAXN 100#define eps 1e-8#define zero(x) (((x)>0?(x):-(x))<eps)struct point{double x,y;};double xmult(point p1,point p2,point p0){return (p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y);}int same_side(point p1,point p2,point l1,point l2){return xmult(l1,p1,l2)*xmult(l1,p2,l2)>eps;}point intersection(point u1,point u2,point v1,point v2){point ret=u1;double t=((u1.x-v1.x)*(v1.y-v2.y)-(u1.y-v1.y)*(v1.x-v2.x))/((u1.x-u2.x)*(v1.y-v2.y)-(u1.y-u2.y)*(v1.x-v2.x));ret.x+=(u2.x-u1.x)*t;ret.y+=(u2.y-u1.y)*t;return ret;}//将多边形沿l1,l2确定的直线切割在side侧切割,保证l1,l2,side不共线void polygon_cut(int& n,point* p,point l1,point l2,point side){point pp[100];int m=0,i;for (i=0;i<n;i++){if (same_side(p[i],side,l1,l2))pp[m++]=p[i];if(!same_side(p[i],p[(i+1)%n],l1,l2)&&!(zero(xmult(p[i],l1,l2))&&zero(xmult(p[(i+1)%n],l1,l2)))) pp[m++]=intersection(p[i],p[(i+1)%n],l1,l2);}for (n=i=0;i<m;i++)if (!i||!zero(pp[i].x-pp[i-1].x)||!zero(pp[i].y-pp[i-1].y))p[n++]=pp[i];if (zero(p[n-1].x-p[0].x)&&zero(p[n-1].y-p[0].y))n--;if (n<3)n=0;}1.5浮点函数//浮点几何函数库#include <math.h>#define eps 1e-8#define zero(x) (((x)>0?(x):-(x))<eps)struct point{double x,y;};struct line{point a,b;};//计算cross product (P1-P0)x(P2-P0)double xmult(point p1,point p2,point p0){return (p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y);}double xmult(double x1,double y1,double x2,double y2,double x0,double y0){ return (x1-x0)*(y2-y0)-(x2-x0)*(y1-y0);}//计算dot product (P1-P0).(P2-P0)double dmult(point p1,point p2,point p0){return (p1.x-p0.x)*(p2.x-p0.x)+(p1.y-p0.y)*(p2.y-p0.y);}double dmult(double x1,double y1,double x2,double y2,double x0,double y0){ return (x1-x0)*(x2-x0)+(y1-y0)*(y2-y0);}//两点距离double distance(point p1,point p2){return sqrt((p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y));}double distance(double x1,double y1,double x2,double y2){return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));}//判三点共线int dots_inline(point p1,point p2,point p3){return zero(xmult(p1,p2,p3));}int dots_inline(double x1,double y1,double x2,double y2,double x3,double y3){ return zero(xmult(x1,y1,x2,y2,x3,y3));}//判点是否在线段上,包括端点int dot_online_in(point p,line l){return zero(xmult(p,l.a,l.b))&&(l.a.x-p.x)*(l.b.x-p.x)<eps&&(l.a.y-p.y)*(l.b.y-p.y)<eps; }int dot_online_in(point p,point l1,point l2){return zero(xmult(p,l1,l2))&&(l1.x-p.x)*(l2.x-p.x)<eps&&(l1.y-p.y)*(l2.y-p.y)<eps;}int dot_online_in(double x,double y,double x1,double y1,double x2,double y2){return zero(xmult(x,y,x1,y1,x2,y2))&&(x1-x)*(x2-x)<eps&&(y1-y)*(y2-y)<eps;}//判点是否在线段上,不包括端点int dot_online_ex(point p,line l){returndot_online_in(p,l)&&(!zero(p.x-l.a.x)||!zero(p.y-l.a.y))&&(!zero(p.x-l.b.x)||!zero(p.y-l.b.y)); }int dot_online_ex(point p,point l1,point l2){returndot_online_in(p,l1,l2)&&(!zero(p.x-l1.x)||!zero(p.y-l1.y))&&(!zero(p.x-l2.x)||!zero(p.y-l2.y)); }int dot_online_ex(double x,double y,double x1,double y1,double x2,double y2){ returndot_online_in(x,y,x1,y1,x2,y2)&&(!zero(x-x1)||!zero(y-y1))&&(!zero(x-x2)||!zero(y-y2));}//判两点在线段同侧,点在线段上返回0int same_side(point p1,point p2,line l){return xmult(l.a,p1,l.b)*xmult(l.a,p2,l.b)>eps;}int same_side(point p1,point p2,point l1,point l2){return xmult(l1,p1,l2)*xmult(l1,p2,l2)>eps;}//判两点在线段异侧,点在线段上返回0int opposite_side(point p1,point p2,line l){return xmult(l.a,p1,l.b)*xmult(l.a,p2,l.b)<-eps;}int opposite_side(point p1,point p2,point l1,point l2){return xmult(l1,p1,l2)*xmult(l1,p2,l2)<-eps;}//判两直线平行int parallel(line u,line v){return zero((u.a.x-u.b.x)*(v.a.y-v.b.y)-(v.a.x-v.b.x)*(u.a.y-u.b.y));}int parallel(point u1,point u2,point v1,point v2){return zero((u1.x-u2.x)*(v1.y-v2.y)-(v1.x-v2.x)*(u1.y-u2.y));}//判两直线垂直int perpendicular(line u,line v){return zero((u.a.x-u.b.x)*(v.a.x-v.b.x)+(u.a.y-u.b.y)*(v.a.y-v.b.y));int perpendicular(point u1,point u2,point v1,point v2){return zero((u1.x-u2.x)*(v1.x-v2.x)+(u1.y-u2.y)*(v1.y-v2.y));}//判两线段相交,包括端点和部分重合int intersect_in(line u,line v){if (!dots_inline(u.a,u.b,v.a)||!dots_inline(u.a,u.b,v.b))return !same_side(u.a,u.b,v)&&!same_side(v.a,v.b,u);return dot_online_in(u.a,v)||dot_online_in(u.b,v)||dot_online_in(v.a,u)||dot_online_in(v.b,u); }int intersect_in(point u1,point u2,point v1,point v2){if (!dots_inline(u1,u2,v1)||!dots_inline(u1,u2,v2))return !same_side(u1,u2,v1,v2)&&!same_side(v1,v2,u1,u2);returndot_online_in(u1,v1,v2)||dot_online_in(u2,v1,v2)||dot_online_in(v1,u1,u2)||dot_online_in(v2,u1,u 2);}//判两线段相交,不包括端点和部分重合int intersect_ex(line u,line v){return opposite_side(u.a,u.b,v)&&opposite_side(v.a,v.b,u);}int intersect_ex(point u1,point u2,point v1,point v2){return opposite_side(u1,u2,v1,v2)&&opposite_side(v1,v2,u1,u2);}//计算两直线交点,注意事先判断直线是否平行!//线段交点请另外判线段相交(同时还是要判断是否平行!)point intersection(line u,line v){point ret=u.a;double t=((u.a.x-v.a.x)*(v.a.y-v.b.y)-(u.a.y-v.a.y)*(v.a.x-v.b.x))/((u.a.x-u.b.x)*(v.a.y-v.b.y)-(u.a.y-u.b.y)*(v.a.x-v.b.x));ret.x+=(u.b.x-u.a.x)*t;ret.y+=(u.b.y-u.a.y)*t;return ret;}point intersection(point u1,point u2,point v1,point v2){point ret=u1;double t=((u1.x-v1.x)*(v1.y-v2.y)-(u1.y-v1.y)*(v1.x-v2.x))/((u1.x-u2.x)*(v1.y-v2.y)-(u1.y-u2.y)*(v1.x-v2.x));ret.x+=(u2.x-u1.x)*t;ret.y+=(u2.y-u1.y)*t;return ret;//点到直线上的最近点point ptoline(point p,line l){point t=p;t.x+=l.a.y-l.b.y,t.y+=l.b.x-l.a.x;return intersection(p,t,l.a,l.b);}point ptoline(point p,point l1,point l2){point t=p;t.x+=l1.y-l2.y,t.y+=l2.x-l1.x;return intersection(p,t,l1,l2);}//点到直线距离double disptoline(point p,line l){return fabs(xmult(p,l.a,l.b))/distance(l.a,l.b);}double disptoline(point p,point l1,point l2){return fabs(xmult(p,l1,l2))/distance(l1,l2);}double disptoline(double x,double y,double x1,double y1,double x2,double y2){ return fabs(xmult(x,y,x1,y1,x2,y2))/distance(x1,y1,x2,y2);}//点到线段上的最近点point ptoseg(point p,line l){point t=p;t.x+=l.a.y-l.b.y,t.y+=l.b.x-l.a.x;if (xmult(l.a,t,p)*xmult(l.b,t,p)>eps)return distance(p,l.a)<distance(p,l.b)?l.a:l.b;return intersection(p,t,l.a,l.b);}point ptoseg(point p,point l1,point l2){point t=p;t.x+=l1.y-l2.y,t.y+=l2.x-l1.x;if (xmult(l1,t,p)*xmult(l2,t,p)>eps)return distance(p,l1)<distance(p,l2)?l1:l2;return intersection(p,t,l1,l2);}//点到线段距离double disptoseg(point p,line l){point t=p;t.x+=l.a.y-l.b.y,t.y+=l.b.x-l.a.x;if (xmult(l.a,t,p)*xmult(l.b,t,p)>eps)return distance(p,l.a)<distance(p,l.b)?distance(p,l.a):distance(p,l.b);return fabs(xmult(p,l.a,l.b))/distance(l.a,l.b);}double disptoseg(point p,point l1,point l2){point t=p;t.x+=l1.y-l2.y,t.y+=l2.x-l1.x;if (xmult(l1,t,p)*xmult(l2,t,p)>eps)return distance(p,l1)<distance(p,l2)?distance(p,l1):distance(p,l2);return fabs(xmult(p,l1,l2))/distance(l1,l2);}//矢量V以P为顶点逆时针旋转angle并放大scale倍point rotate(point v,point p,double angle,double scale){point ret=p;v.x-=p.x,v.y-=p.y;p.x=scale*cos(angle);p.y=scale*sin(angle);ret.x+=v.x*p.x-v.y*p.y;ret.y+=v.x*p.y+v.y*p.x;return ret;}1.6面积#include <math.h>struct point{double x,y;};//计算cross product (P1-P0)x(P2-P0)double xmult(point p1,point p2,point p0){return (p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y);}double xmult(double x1,double y1,double x2,double y2,double x0,double y0){ return (x1-x0)*(y2-y0)-(x2-x0)*(y1-y0);}//计算三角形面积,输入三顶点double area_triangle(point p1,point p2,point p3){return fabs(xmult(p1,p2,p3))/2;}double area_triangle(double x1,double y1,double x2,double y2,double x3,double y3){ return fabs(xmult(x1,y1,x2,y2,x3,y3))/2;}//计算三角形面积,输入三边长double area_triangle(double a,double b,double c){double s=(a+b+c)/2;return sqrt(s*(s-a)*(s-b)*(s-c));}//计算多边形面积,顶点按顺时针或逆时针给出double area_polygon(int n,point* p){double s1=0,s2=0;int i;for (i=0;i<n;i++)s1+=p[(i+1)%n].y*p[i].x,s2+=p[(i+1)%n].y*p[(i+2)%n].x;return fabs(s1-s2)/2;}1.7球面#include <math.h>const double pi=acos(-1);//计算圆心角lat表示纬度,-90<=w<=90,lng表示经度//返回两点所在大圆劣弧对应圆心角,0<=angle<=pidouble angle(double lng1,double lat1,double lng2,double lat2){ double dlng=fabs(lng1-lng2)*pi/180;while (dlng>=pi+pi)dlng-=pi+pi;if (dlng>pi)dlng=pi+pi-dlng;lat1*=pi/180,lat2*=pi/180;return acos(cos(lat1)*cos(lat2)*cos(dlng)+sin(lat1)*sin(lat2));}//计算距离,r为球半径double line_dist(double r,double lng1,double lat1,double lng2,double lat2){ double dlng=fabs(lng1-lng2)*pi/180;while (dlng>=pi+pi)dlng-=pi+pi;if (dlng>pi)dlng=pi+pi-dlng;lat1*=pi/180,lat2*=pi/180;return r*sqrt(2-2*(cos(lat1)*cos(lat2)*cos(dlng)+sin(lat1)*sin(lat2))); }//计算球面距离,r为球半径inline double sphere_dist(double r,double lng1,double lat1,double lng2,double lat2){ return r*angle(lng1,lat1,lng2,lat2);}1.8三角形#include <math.h>struct point{double x,y;};struct line{point a,b;};double distance(point p1,point p2){return sqrt((p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y));}point intersection(line u,line v){point ret=u.a;double t=((u.a.x-v.a.x)*(v.a.y-v.b.y)-(u.a.y-v.a.y)*(v.a.x-v.b.x))/((u.a.x-u.b.x)*(v.a.y-v.b.y)-(u.a.y-u.b.y)*(v.a.x-v.b.x));ret.x+=(u.b.x-u.a.x)*t;ret.y+=(u.b.y-u.a.y)*t;return ret;}//外心point circumcenter(point a,point b,point c){line u,v;u.a.x=(a.x+b.x)/2;u.a.y=(a.y+b.y)/2;u.b.x=u.a.x-a.y+b.y;u.b.y=u.a.y+a.x-b.x;v.a.x=(a.x+c.x)/2;v.a.y=(a.y+c.y)/2;v.b.x=v.a.x-a.y+c.y;v.b.y=v.a.y+a.x-c.x;return intersection(u,v);}//内心point incenter(point a,point b,point c){line u,v;double m,n;u.a=a;m=atan2(b.y-a.y,b.x-a.x);n=atan2(c.y-a.y,c.x-a.x);u.b.x=u.a.x+cos((m+n)/2);u.b.y=u.a.y+sin((m+n)/2);v.a=b;m=atan2(a.y-b.y,a.x-b.x);n=atan2(c.y-b.y,c.x-b.x);v.b.x=v.a.x+cos((m+n)/2);v.b.y=v.a.y+sin((m+n)/2);return intersection(u,v);}//垂心point perpencenter(point a,point b,point c){line u,v;u.a=c;u.b.x=u.a.x-a.y+b.y;u.b.y=u.a.y+a.x-b.x;v.a=b;v.b.x=v.a.x-a.y+c.y;v.b.y=v.a.y+a.x-c.x;return intersection(u,v);}//重心//到三角形三顶点距离的平方和最小的点//三角形内到三边距离之积最大的点point barycenter(point a,point b,point c){line u,v;u.a.x=(a.x+b.x)/2;u.a.y=(a.y+b.y)/2;u.b=c;v.a.x=(a.x+c.x)/2;v.a.y=(a.y+c.y)/2;v.b=b;return intersection(u,v);}//费马点//到三角形三顶点距离之和最小的点point fermentpoint(point a,point b,point c){point u,v;double step=fabs(a.x)+fabs(a.y)+fabs(b.x)+fabs(b.y)+fabs(c.x)+fabs(c.y);int i,j,k;u.x=(a.x+b.x+c.x)/3;u.y=(a.y+b.y+c.y)/3;while (step>1e-10)for (k=0;k<10;step/=2,k++)for (i=-1;i<=1;i++)for (j=-1;j<=1;j++){v.x=u.x+step*i;v.y=u.y+step*j;if(distance(u,a)+distance(u,b)+distance(u,c)>distance(v,a)+distance(v,b)+distance(v,c))u=v;}return u;}1.9三维几何//三维几何函数库#include <math.h>#define eps 1e-8#define zero(x) (((x)>0?(x):-(x))<eps)struct point3{double x,y,z;};struct line3{point3 a,b;};struct plane3{point3 a,b,c;};//计算cross product U x Vpoint3 xmult(point3 u,point3 v){point3 ret;ret.x=u.y*v.z-v.y*u.z;ret.y=u.z*v.x-u.x*v.z;ret.z=u.x*v.y-u.y*v.x;return ret;}//计算dot product U . Vdouble dmult(point3 u,point3 v){return u.x*v.x+u.y*v.y+u.z*v.z;}//矢量差U - Vpoint3 subt(point3 u,point3 v){point3 ret;ret.x=u.x-v.x;ret.y=u.y-v.y;ret.z=u.z-v.z;return ret;}//取平面法向量point3 pvec(plane3 s){return xmult(subt(s.a,s.b),subt(s.b,s.c));}point3 pvec(point3 s1,point3 s2,point3 s3){return xmult(subt(s1,s2),subt(s2,s3));}//两点距离,单参数取向量大小double distance(point3 p1,point3 p2){return sqrt((p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y)+(p1.z-p2.z)*(p1.z-p2.z)); }//向量大小double vlen(point3 p){return sqrt(p.x*p.x+p.y*p.y+p.z*p.z);}//判三点共线int dots_inline(point3 p1,point3 p2,point3 p3){return vlen(xmult(subt(p1,p2),subt(p2,p3)))<eps;}//判四点共面int dots_onplane(point3 a,point3 b,point3 c,point3 d){return zero(dmult(pvec(a,b,c),subt(d,a)));}//判点是否在线段上,包括端点和共线int dot_online_in(point3 p,line3 l){return zero(vlen(xmult(subt(p,l.a),subt(p,l.b))))&&(l.a.x-p.x)*(l.b.x-p.x)<eps&& (l.a.y-p.y)*(l.b.y-p.y)<eps&&(l.a.z-p.z)*(l.b.z-p.z)<eps;}int dot_online_in(point3 p,point3 l1,point3 l2){return zero(vlen(xmult(subt(p,l1),subt(p,l2))))&&(l1.x-p.x)*(l2.x-p.x)<eps&& (l1.y-p.y)*(l2.y-p.y)<eps&&(l1.z-p.z)*(l2.z-p.z)<eps;}//判点是否在线段上,不包括端点int dot_online_ex(point3 p,line3 l){return dot_online_in(p,l)&&(!zero(p.x-l.a.x)||!zero(p.y-l.a.y)||!zero(p.z-l.a.z))&&(!zero(p.x-l.b.x)||!zero(p.y-l.b.y)||!zero(p.z-l.b.z));}int dot_online_ex(point3 p,point3 l1,point3 l2){return dot_online_in(p,l1,l2)&&(!zero(p.x-l1.x)||!zero(p.y-l1.y)||!zero(p.z-l1.z))&& (!zero(p.x-l2.x)||!zero(p.y-l2.y)||!zero(p.z-l2.z));}//判点是否在空间三角形上,包括边界,三点共线无意义int dot_inplane_in(point3 p,plane3 s){return zero(vlen(xmult(subt(s.a,s.b),subt(s.a,s.c)))-vlen(xmult(subt(p,s.a),subt(p,s.b)))- vlen(xmult(subt(p,s.b),subt(p,s.c)))-vlen(xmult(subt(p,s.c),subt(p,s.a))));}int dot_inplane_in(point3 p,point3 s1,point3 s2,point3 s3){return zero(vlen(xmult(subt(s1,s2),subt(s1,s3)))-vlen(xmult(subt(p,s1),subt(p,s2)))- vlen(xmult(subt(p,s2),subt(p,s3)))-vlen(xmult(subt(p,s3),subt(p,s1))));}//判点是否在空间三角形上,不包括边界,三点共线无意义int dot_inplane_ex(point3 p,plane3 s){return dot_inplane_in(p,s)&&vlen(xmult(subt(p,s.a),subt(p,s.b)))>eps&&vlen(xmult(subt(p,s.b),subt(p,s.c)))>eps&&vlen(xmult(subt(p,s.c),subt(p,s.a)))>eps; }int dot_inplane_ex(point3 p,point3 s1,point3 s2,point3 s3){return dot_inplane_in(p,s1,s2,s3)&&vlen(xmult(subt(p,s1),subt(p,s2)))>eps&& vlen(xmult(subt(p,s2),subt(p,s3)))>eps&&vlen(xmult(subt(p,s3),subt(p,s1)))>eps; }//判两点在线段同侧,点在线段上返回0,不共面无意义int same_side(point3 p1,point3 p2,line3 l){return dmult(xmult(subt(l.a,l.b),subt(p1,l.b)),xmult(subt(l.a,l.b),subt(p2,l.b)))>eps;}int same_side(point3 p1,point3 p2,point3 l1,point3 l2){return dmult(xmult(subt(l1,l2),subt(p1,l2)),xmult(subt(l1,l2),subt(p2,l2)))>eps;}//判两点在线段异侧,点在线段上返回0,不共面无意义int opposite_side(point3 p1,point3 p2,line3 l){return dmult(xmult(subt(l.a,l.b),subt(p1,l.b)),xmult(subt(l.a,l.b),subt(p2,l.b)))<-eps;}int opposite_side(point3 p1,point3 p2,point3 l1,point3 l2){return dmult(xmult(subt(l1,l2),subt(p1,l2)),xmult(subt(l1,l2),subt(p2,l2)))<-eps;}//判两点在平面同侧,点在平面上返回0int same_side(point3 p1,point3 p2,plane3 s){return dmult(pvec(s),subt(p1,s.a))*dmult(pvec(s),subt(p2,s.a))>eps;}int same_side(point3 p1,point3 p2,point3 s1,point3 s2,point3 s3){return dmult(pvec(s1,s2,s3),subt(p1,s1))*dmult(pvec(s1,s2,s3),subt(p2,s1))>eps; }//判两点在平面异侧,点在平面上返回0int opposite_side(point3 p1,point3 p2,plane3 s){return dmult(pvec(s),subt(p1,s.a))*dmult(pvec(s),subt(p2,s.a))<-eps;}int opposite_side(point3 p1,point3 p2,point3 s1,point3 s2,point3 s3){return dmult(pvec(s1,s2,s3),subt(p1,s1))*dmult(pvec(s1,s2,s3),subt(p2,s1))<-eps; }//判两直线平行int parallel(line3 u,line3 v){return vlen(xmult(subt(u.a,u.b),subt(v.a,v.b)))<eps;}int parallel(point3 u1,point3 u2,point3 v1,point3 v2){return vlen(xmult(subt(u1,u2),subt(v1,v2)))<eps;}//判两平面平行int parallel(plane3 u,plane3 v){return vlen(xmult(pvec(u),pvec(v)))<eps;}int parallel(point3 u1,point3 u2,point3 u3,point3 v1,point3 v2,point3 v3){ return vlen(xmult(pvec(u1,u2,u3),pvec(v1,v2,v3)))<eps;}//判直线与平面平行int parallel(line3 l,plane3 s){return zero(dmult(subt(l.a,l.b),pvec(s)));}int parallel(point3 l1,point3 l2,point3 s1,point3 s2,point3 s3){return zero(dmult(subt(l1,l2),pvec(s1,s2,s3)));}//判两直线垂直int perpendicular(line3 u,line3 v){return zero(dmult(subt(u.a,u.b),subt(v.a,v.b)));}int perpendicular(point3 u1,point3 u2,point3 v1,point3 v2){return zero(dmult(subt(u1,u2),subt(v1,v2)));}//判两平面垂直int perpendicular(plane3 u,plane3 v){return zero(dmult(pvec(u),pvec(v)));}int perpendicular(point3 u1,point3 u2,point3 u3,point3 v1,point3 v2,point3 v3){ return zero(dmult(pvec(u1,u2,u3),pvec(v1,v2,v3)));}//判直线与平面平行int perpendicular(line3 l,plane3 s){return vlen(xmult(subt(l.a,l.b),pvec(s)))<eps;}int perpendicular(point3 l1,point3 l2,point3 s1,point3 s2,point3 s3){return vlen(xmult(subt(l1,l2),pvec(s1,s2,s3)))<eps;}//判两线段相交,包括端点和部分重合int intersect_in(line3 u,line3 v){if (!dots_onplane(u.a,u.b,v.a,v.b))return 0;if (!dots_inline(u.a,u.b,v.a)||!dots_inline(u.a,u.b,v.b))return !same_side(u.a,u.b,v)&&!same_side(v.a,v.b,u);return dot_online_in(u.a,v)||dot_online_in(u.b,v)||dot_online_in(v.a,u)||dot_online_in(v.b,u); }int intersect_in(point3 u1,point3 u2,point3 v1,point3 v2){if (!dots_onplane(u1,u2,v1,v2))return 0;if (!dots_inline(u1,u2,v1)||!dots_inline(u1,u2,v2))return !same_side(u1,u2,v1,v2)&&!same_side(v1,v2,u1,u2);returndot_online_in(u1,v1,v2)||dot_online_in(u2,v1,v2)||dot_online_in(v1,u1,u2)||dot_online_in(v2,u1,u 2);}//判两线段相交,不包括端点和部分重合int intersect_ex(line3 u,line3 v){return dots_onplane(u.a,u.b,v.a,v.b)&&opposite_side(u.a,u.b,v)&&opposite_side(v.a,v.b,u); }int intersect_ex(point3 u1,point3 u2,point3 v1,point3 v2){returndots_onplane(u1,u2,v1,v2)&&opposite_side(u1,u2,v1,v2)&&opposite_side(v1,v2,u1,u2);}//判线段与空间三角形相交,包括交于边界和(部分)包含int intersect_in(line3 l,plane3 s){return !same_side(l.a,l.b,s)&&!same_side(s.a,s.b,l.a,l.b,s.c)&& !same_side(s.b,s.c,l.a,l.b,s.a)&&!same_side(s.c,s.a,l.a,l.b,s.b);}int intersect_in(point3 l1,point3 l2,point3 s1,point3 s2,point3 s3){ return !same_side(l1,l2,s1,s2,s3)&&!same_side(s1,s2,l1,l2,s3)&& !same_side(s2,s3,l1,l2,s1)&&!same_side(s3,s1,l1,l2,s2);}//判线段与空间三角形相交,不包括交于边界和(部分)包含int intersect_ex(line3 l,plane3 s){return opposite_side(l.a,l.b,s)&&opposite_side(s.a,s.b,l.a,l.b,s.c)&& opposite_side(s.b,s.c,l.a,l.b,s.a)&&opposite_side(s.c,s.a,l.a,l.b,s.b); }int intersect_ex(point3 l1,point3 l2,point3 s1,point3 s2,point3 s3){ return opposite_side(l1,l2,s1,s2,s3)&&opposite_side(s1,s2,l1,l2,s3)&& opposite_side(s2,s3,l1,l2,s1)&&opposite_side(s3,s1,l1,l2,s2);}//计算两直线交点,注意事先判断直线是否共面和平行!//线段交点请另外判线段相交(同时还是要判断是否平行!)point3 intersection(line3 u,line3 v){point3 ret=u.a;double t=((u.a.x-v.a.x)*(v.a.y-v.b.y)-(u.a.y-v.a.y)*(v.a.x-v.b.x))/((u.a.x-u.b.x)*(v.a.y-v.b.y)-(u.a.y-u.b.y)*(v.a.x-v.b.x));ret.x+=(u.b.x-u.a.x)*t;ret.y+=(u.b.y-u.a.y)*t;ret.z+=(u.b.z-u.a.z)*t;return ret;}point3 intersection(point3 u1,point3 u2,point3 v1,point3 v2){point3 ret=u1;double t=((u1.x-v1.x)*(v1.y-v2.y)-(u1.y-v1.y)*(v1.x-v2.x))/((u1.x-u2.x)*(v1.y-v2.y)-(u1.y-u2.y)*(v1.x-v2.x));ret.x+=(u2.x-u1.x)*t;ret.y+=(u2.y-u1.y)*t;ret.z+=(u2.z-u1.z)*t;return ret;}//计算直线与平面交点,注意事先判断是否平行,并保证三点不共线!。
ACM培训大纲
实用标准文案ACM培训大纲基础内容:数据结构——》搜索——》图论DP数论博弈中级内容数据结构网络流第一章搜索1.二分搜索三分搜索2.栈 3.队列 4.深搜 5.广搜 6.第二章数据结构1.优先队列并查集 2.二叉搜索树3.线段树(单点更新) 4.Trie5.精彩文档.实用标准文案第三章图论1.图的表示1.1二维数组1.2邻接表1.3前向星2.图的遍历2.1双连通分量2.2拓扑排序3.最短路3.1迪杰斯特拉3.2弗洛伊德3.3SPFA4.匹配匈牙利算法5.生成树6.网络流简介第四章动态规划1.状态转移方程2.引入2.10-1背包2.2硬币问题2.3矩阵链乘3.区间DP4.按位DP5.树形DP6.状压DP第五章数论1.欧几里得扩展欧几里得 2.因数分解3.费马小定理 4.欧拉定理 5.素数6.6.1筛法6.2素数判定6.2.1O(√n)方法精彩文档.实用标准文案6.2.2Miller-rabin测试第六章博弈1.Nim和2.SG函数第七章中级数据结构1.树状数组RMQ 2.KMP3.AC自动机4.线段树(区间更新)5.第八章图论进阶1.网络流问题精彩文档.实用标准文案综述在很多人眼里,东北大学秦皇岛分校不算是985高校。
所以我们要用自己的能力证明我们有985的实力。
ACM是计算机界认可度最高的一个比赛,可以说只要区域赛有过奖牌,国内任何IT公司没有理由不要。
同时,在高校之中,对一个大学计算机专业的评价,大部分人也会首先看ACM 的水平。
将ACM打出学校,在国内打出一定成绩,对扩大我校影响力很有帮助。
考虑到本校暂时没有进行专题训练的出题能力,专题训练的题目主要从UESTC 2014年集训队专题训练中获取,再加上从别的OJ上找一些题目。
训练的平台设置在华中科技大学的vertual judge上面。
本人将在毕业之前承担培训任务。
在2015学年开始之前,培训计划为每两周一次,中间空闲的时间由大二或者大一熟悉C++的同学给不熟悉C++的同学进行基础的讲解。
线段树的合并
线段树
• 具体实现不再赘述 • 一些常见的问题譬如维护区间和由于其特殊性,可以在支
持对连续的一段元素做出某种程度的修改的前提下,仍然 高效地维护区间和。一般情况下不一定能这么做。 • 有时也用来实现map,这时key是字长内的整数,同时能维 护key连续的一些元素的信息。
线段树的特点
• 当确定了元素个数n,或者key的范围[1,U],建出的线段树 形态是唯一的。
线段树的合并
——不为人知的实用技巧
杭州二中 黄嘉泰
线段树?
• OI中最常用的数据结构 • 形式化的线段树:
有一列元素 a1, a2 ,..., an S
S上有二元运算 ,使得对于任意a,b S ,都有a bS, 并且 满足结合律。({S,}是半群) 另外, 运算必须能高效地计算完成,譬如O(1)。
SPOJ COT3
• 给定一棵n个点的有根树,每个点是黑的或者白的。 • 两个人在树上博弈,轮流进行以下操作: • 选择一个当前为白色的点u,把u到根路径上的所有点涂黑 • 不能操作者输 • 判断两人都用最优策略进行游戏时的胜负情况,并输出第
一个人第一步所有可行的决策。
SPOJ COT3
• 出处:2010集训队 陈高远 • 数据加强 • 由公平组合游戏的性质不难想到以下的dp: • dp[u]表示只考虑子树u的SG值 • g[u][v]表示只考虑子树u,v是u的某个白色后代(可能为u),
数来的大。
另一种风格的线段树
• 以合并操作为核心,我们可以写出另一种风格的线段树 • 关键操作:
– merge_leaf过程 – 连接操作 – merge过程 – make_leaf过程
• 操作都自顶向下,可以方便地持久化
线段树合并VS启发式合并
ACM大牛总结的线段树专辑,超经典的
【完全版】线段树很早前写的那篇线段树专辑至今一直是本博客阅读点击量最大的一片文章,当时觉得挺自豪的,还去pku打广告,但是现在我自己都不太好意思去看那篇文章了,觉得当时的代码风格实在是太丑了,很多线段树的初学者可能就是看着这篇文章来练习的,如果不小心被我培养出了这么糟糕的风格,实在是过意不去,正好过几天又要给集训队讲解线段树,所以决定把这些题目重新写一遍,顺便把近年我接触到的一些新题更新上去~;并且学习了splay等更高级的数据结构后对线段树的体会有更深了一层,线段树的写法也就比以前飘逸,简洁且方便多了.在代码前先介绍一些我的线段树风格:∙maxn是题目给的最大区间,而节点数要开4倍,确切的来说节点数要开大于maxn的最小2x的两倍∙lson和rson分辨表示结点的左儿子和右儿子,由于每次传参数的时候都固定是这几个变量,所以可以用预定于比较方便的表示∙以前的写法是另外开两个个数组记录每个结点所表示的区间,其实这个区间不必保存,一边算一边传下去就行,只需要写函数的时候多两个参数,结合lson和rson的预定义可以很方便∙PushUP(int rt)是把当前结点的信息更新到父结点∙PushDown(int rt)是把当前结点的信息更新给儿子结点∙rt表示当前子树的根(root),也就是当前所在的结点整理这些题目后我觉得线段树的题目整体上可以分成以下四个部分:∙单点更新:最最基础的线段树,只更新叶子节点,然后把信息用PushUP(int r)这个函数更新上来o hdu1166 敌兵布阵题意:O(-1)思路:O(-1)线段树功能:update:单点增减query:区间求和?View Code CPP1 2 3 4 5 6 7 8 910111213 #include <cstdio>#define lson l , m , rt << 1#define rson m + 1 , r , rt << 1 | 1constint maxn =55555;int sum[maxn<<2];void PushUP(int rt){sum[rt]= sum[rt<<1]+ sum[rt<<1|1]; }void build(int l,int r,int rt){if(l == r){scanf("%d",&sum[rt]);return;1415161718192021222324252627282930313233343536373839404142434445464748495051525354555657}int m =(l + r)>>1;build(lson);build(rson);PushUP(rt);}void update(int p,int add,int l,int r,int rt){if(l == r){sum[rt]+= add;return;}int m =(l + r)>>1;if(p <= m) update(p , add , lson);else update(p , add , rson);PushUP(rt);}int query(int L,int R,int l,int r,int rt){if(L <= l && r <= R){return sum[rt];}int m =(l + r)>>1;int ret =0;if(L <= m) ret += query(L , R , lson);if(R > m) ret += query(L , R , rson);return ret;}int main(){int T , n;scanf("%d",&T);for(int cas =1; cas <= T ; cas ++){printf("Case %d:\n",cas);scanf("%d",&n);build(1 , n , 1);char op[10];while(scanf("%s",op)){if(op[0]=='E')break;int a , b;scanf("%d%d",&a,&b);if(op[0]=='Q')printf("%d\n",query(a , b , 1 , n , 1));elseif(op[0]=='S') update(a , -b , 1 , n , 1);else update(a , b , 1 , n , 1);}}return0;58 }o hdu1754 I Hate It题意:O(-1)思路:O(-1)线段树功能:update:单点替换query:区间最值?View Code CPP1 2 3 4 5 6 7 8 91011121314151617181920212223242526272829303132333435363738 #include <cstdio>#include <algorithm>usingnamespace std;#define lson l , m , rt << 1#define rson m + 1 , r , rt << 1 | 1constint maxn =222222;int MAX[maxn<<2];void PushUP(int rt){MAX[rt]= max(MAX[rt<<1] , MAX[rt<<1|1]);}void build(int l,int r,int rt){if(l == r){scanf("%d",&MAX[rt]);return;}int m =(l + r)>>1;build(lson);build(rson);PushUP(rt);}void update(int p,int sc,int l,int r,int rt){if(l == r){MAX[rt]= sc;return;}int m =(l + r)>>1;if(p <= m) update(p , sc , lson);else update(p , sc , rson);PushUP(rt);}int query(int L,int R,int l,int r,int rt){if(L <= l && r <= R){return MAX[rt];}int m =(l + r)>>1;int ret =0;if(L <= m) ret = max(ret , query(L , R , lson));3940414243444546474849505152535455if(R > m) ret = max(ret , query(L , R , rson));return ret;}int main(){int n , m;while(~scanf("%d%d",&n,&m)){build(1 , n , 1);while(m --){char op[2];int a , b;scanf("%s%d%d",op,&a,&b);if(op[0]=='Q')printf("%d\n",query(a , b , 1 , n , 1));else update(a , b , 1 , n , 1);}}return0;}o hdu1394 Minimum Inversion Number题意:求Inversion后的最小逆序数思路:用O(nlogn)复杂度求出最初逆序数后,就可以用O(1)的复杂度分别递推出其他解线段树功能:update:单点增减query:区间求和?View Code CPP1 2 3 4 5 6 7 8 9101112131415161718192021 #include <cstdio>#include <algorithm>usingnamespace std;#define lson l , m , rt << 1#define rson m + 1 , r , rt << 1 | 1constint maxn =5555;int sum[maxn<<2];void PushUP(int rt){sum[rt]= sum[rt<<1]+ sum[rt<<1|1]; }void build(int l,int r,int rt){sum[rt]=0;if(l == r)return;int m =(l + r)>>1;build(lson);build(rson);}void update(int p,int l,int r,int rt){if(l == r){sum[rt]++;22232425262728293031323334353637383940414243444546474849505152535455565758return;}int m =(l + r)>>1;if(p <= m) update(p , lson);else update(p , rson);PushUP(rt);}int query(int L,int R,int l,int r,int rt){if(L <= l && r <= R){return sum[rt];}int m =(l + r)>>1;int ret =0;if(L <= m) ret += query(L , R , lson);if(R > m) ret += query(L , R , rson);return ret;}int x[maxn];int main(){int n;while(~scanf("%d",&n)){build(0 , n -1 , 1);int sum =0;for(int i =0; i < n ; i ++){scanf("%d",&x[i]);sum += query(x[i] , n -1 , 0 , n -1 , 1);update(x[i] , 0 , n -1 , 1);}int ret = sum;for(int i =0; i < n ; i ++){sum += n - x[i]- x[i]-1;ret = min(ret , sum);}printf("%d\n",ret);}return0;}o hdu2795 Billboard题意:h*w的木板,放进一些1*L的物品,求每次放空间能容纳且最上边的位子思路:每次找到最大值的位子,然后减去L线段树功能:query:区间求最大值的位子(直接把update的操作在query里做了) ?View Code CPP1 2 #include <cstdio>#include <algorithm>3 4 5 6 7 8 910 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 usingnamespace std ;#define lson l , m , rt << 1 #define rson m + 1 , r , rt << 1 | 1 constint maxn =222222; int h , w , n ; int MAX [maxn <<2]; void PushUP (int rt ){ MAX [rt ]= max (MAX [rt <<1] , MAX [rt <<1|1]);}void build (int l,int r,int rt ){ MAX [rt ]= w ; if (l == r )return ; int m =(l + r )>>1; build (lson ); build (rson );}int query (int x,int l,int r,int rt ){ if (l == r ){ MAX [rt ]-= x ; return l ;}int m =(l + r )>>1;int ret =(MAX [rt <<1]>= x )? query (x , lson ): query (x , rson ); PushUP (rt ); return ret ;}int main (){ while (~scanf ("%d%d%d",&h,&w,&n )){ if (h > n ) h = n ; build (1 , h , 1); while (n --){ int x ;scanf ("%d",&x ); if (MAX [1]< x )puts ("-1");else printf ("%d \n ",query (x , 1 , h , 1));}} return 0;}练习:成段更新(通常这对初学者来说是一道坎),需要用到延迟标记(或者说懒惰标记),简单来说就是每次更新的时候不要更新到底,用延迟标记使得更新延迟到下次需要更新or询问到的时候o hdu1698 Just a Hook题意:O(-1)思路:O(-1)线段树功能:update:成段替换(由于只query一次总区间,所以可以直接输出1结点的信息)?View Code CPP1 2 3 4 5 6 7 8 91011121314151617181920212223242526272829303132333435 #include <cstdio>#include <algorithm>usingnamespace std;#define lson l , m , rt << 1#define rson m + 1 , r , rt << 1 | 1constint maxn =111111;int h , w , n;int col[maxn<<2];int sum[maxn<<2];void PushUp(int rt){sum[rt]= sum[rt<<1]+ sum[rt<<1|1];}void PushDown(int rt,int m){if(col[rt]){col[rt<<1]= col[rt<<1|1]= col[rt];sum[rt<<1]=(m -(m >>1))* col[rt];sum[rt<<1|1]=(m >>1)* col[rt];col[rt]=0;}}void build(int l,int r,int rt){col[rt]=0;sum[rt]=1;if(l == r)return;int m =(l + r)>>1;build(lson);build(rson);PushUp(rt);}void update(int L,int R,int c,int l,int r,int rt){if(L <= l && r <= R){col[rt]= c;sum[rt]= c *(r - l +1);return;36373839404142434445464748495051525354555657}PushDown(rt , r - l +1);int m =(l + r)>>1;if(L <= m) update(L , R , c , lson);if(R > m) update(L , R , c , rson);PushUp(rt);}int main(){int T , n , m;scanf("%d",&T);for(int cas =1; cas <= T ; cas ++){scanf("%d%d",&n,&m);build(1 , n , 1);while(m --){int a , b , c;scanf("%d%d%d",&a,&b,&c);update(a , b , c , 1 , n , 1);}printf("Case %d: The total value of the hook is %d.\n",cas , sum[1]);}return0;}o poj3468 A Simple Problem with Integers 题意:O(-1)思路:O(-1)线段树功能:update:成段增减query:区间求和?View Code CPP1 2 3 4 5 6 7 8 91011121314151617 #include <cstdio>#include <algorithm>usingnamespace std;#define lson l , m , rt << 1#define rson m + 1 , r , rt << 1 | 1#define LL long longconstint maxn =111111;LL add[maxn<<2];LL sum[maxn<<2];void PushUp(int rt){sum[rt]= sum[rt<<1]+ sum[rt<<1|1]; }void PushDown(int rt,int m){if(add[rt]){add[rt<<1]+= add[rt];add[rt<<1|1]+= add[rt];1819202122232425262728293031323334353637383940414243444546474849505152535455565758596061sum[rt<<1]+= add[rt]*(m -(m >>1));sum[rt<<1|1]+= add[rt]*(m >>1);add[rt]=0;}}void build(int l,int r,int rt){add[rt]=0;if(l == r){scanf("%lld",&sum[rt]);return;}int m =(l + r)>>1;build(lson);build(rson);PushUp(rt);}void update(int L,int R,int c,int l,int r,int rt){if(L <= l && r <= R){add[rt]+= c;sum[rt]+=(LL)c *(r - l +1);return;}PushDown(rt , r - l +1);int m =(l + r)>>1;if(L <= m) update(L , R , c , lson);if(m < R) update(L , R , c , rson);PushUp(rt);}LL query(int L,int R,int l,int r,int rt){if(L <= l && r <= R){return sum[rt];}PushDown(rt , r - l +1);int m =(l + r)>>1;LL ret =0;if(L <= m) ret += query(L , R , lson);if(m < R) ret += query(L , R , rson);return ret;}int main(){int N , Q;scanf("%d%d",&N,&Q);build(1 , N , 1);while(Q --){62636465666768697071727374char op[2];int a , b , c;scanf("%s",op);if(op[0]=='Q'){scanf("%d%d",&a,&b);printf("%lld\n",query(a , b , 1 , N , 1));}else{scanf("%d%d%d",&a,&b,&c);update(a , b , c , 1 , N , 1);}}return0;}o poj2528 Mayor’s posters题意:在墙上贴海报,海报可以互相覆盖,问最后可以看见几张海报思路:这题数据范围很大,直接搞超时+超内存,需要离散化:离散化简单的来说就是只取我们需要的值来用,比如说区间[1000,2000],[1990,2012] 我们用不到[-∞,999][1001,1989][1991,1999][2001,2011][2013,+∞]这些值,所以我只需要1000,1990,2000,2012就够了,将其分别映射到0,1,2,3,在于复杂度就大大的降下来了所以离散化要保存所有需要用到的值,排序后,分别映射到1~n,这样复杂度就会小很多很多而这题的难点在于每个数字其实表示的是一个单位长度(并且一个点),这样普通的离散化会造成许多错误(包括我以前的代码,poj这题数据奇弱)给出下面两个简单的例子应该能体现普通离散化的缺陷:1-10 1-4 5-101-10 1-4 6-10为了解决这种缺陷,我们可以在排序后的数组上加些处理,比如说[1,2,6,10]如果相邻数字间距大于1的话,在其中加上任意一个数字,比如加成[1,2,3,6,7,10],然后再做线段树就好了.线段树功能:update:成段替换query:简单hash?View Code CPP1 2 3 4 5 6 7 8 9101112 #include <cstdio>#include <cstring>#include <algorithm> usingnamespace std;#define lson l , m , rt << 1#define rson m + 1 , r , rt << 1 | 1constint maxn =11111;bool hash[maxn];int li[maxn] , ri[maxn];int X[maxn*3];int col[maxn<<4];1314151617181920212223242526272829303132333435363738394041424344454647484950515253545556 int cnt;void PushDown(int rt){if(col[rt]!=-1){col[rt<<1]= col[rt<<1|1]= col[rt];col[rt]=-1;}}void update(int L,int R,int c,int l,int r,int rt){if(L <= l && r <= R){col[rt]= c;return;}PushDown(rt);int m =(l + r)>>1;if(L <= m) update(L , R , c , lson);if(m < R) update(L , R , c , rson);}void query(int l,int r,int rt){if(col[rt]!=-1){if(!hash[col[rt]]) cnt ++;hash[ col[rt]]=true;return;}if(l == r)return;int m =(l + r)>>1;query(lson);query(rson);}int Bin(int key,int n,int X[]){int l =0 , r = n -1;while(l <= r){int m =(l + r)>>1;if(X[m]== key)return m;if(X[m]< key) l = m +1;else r = m -1;}return-1;}int main(){int T , n;scanf("%d",&T);while(T --){scanf("%d",&n);57585960616263646566676869707172737475767778798081828384int nn =0;for(int i =0; i < n ; i ++){scanf("%d%d",&li[i] , &ri[i]);X[nn++]= li[i];X[nn++]= ri[i];}sort(X , X + nn);int m =1;for(int i =1; i < nn; i ++){if(X[i]!= X[i-1]) X[m ++]= X[i];}for(int i = m -1; i >0; i --){if(X[i]!= X[i-1]+1) X[m ++]= X[i-1]+1;}sort(X , X + m);memset(col , -1 , sizeof(col));for(int i =0; i < n ; i ++){int l = Bin(li[i] , m , X);int r = Bin(ri[i] , m , X);update(l , r , i , 0 , m , 1);}cnt =0;memset(hash , false , sizeof(hash));query(0 , m , 1);printf("%d\n",cnt);}return0;}o poj3225 Help with Intervals题意:区间操作,交,并,补等思路:我们一个一个操作来分析:(用0和1表示是否包含区间,-1表示该区间内既有包含又有不包含)U:把区间[l,r]覆盖成1I:把[-∞,l)(r,∞]覆盖成0D:把区间[l,r]覆盖成0C:把[-∞,l)(r,∞]覆盖成0 , 且[l,r]区间0/1互换S:[l,r]区间0/1互换成段覆盖的操作很简单,比较特殊的就是区间0/1互换这个操作,我们可以称之为异或操作很明显我们可以知道这个性质:当一个区间被覆盖后,不管之前有没有异或标记都没有意义了所以当一个节点得到覆盖标记时把异或标记清空而当一个节点得到异或标记的时候,先判断覆盖标记,如果是0或1,直接改变一下覆盖标记,不然的话改变异或标记开区间闭区间只要数字乘以2就可以处理(偶数表示端点,奇数表示两端点间的区间)线段树功能:update:成段替换,区间异或query:简单hash?View Code CPP1 2 3 4 5 6 7 8 9101112131415161718192021222324252627282930313233343536373839 #include <cstdio>#include <cstring>#include <cctype>#include <algorithm>usingnamespace std;#define lson l , m , rt << 1#define rson m + 1 , r , rt << 1 | 1constint maxn =131072;bool hash[maxn];int cover[maxn<<2];int XOR[maxn<<2];void FXOR(int rt){if(cover[rt]!=-1) cover[rt]^=1;else XOR[rt]^=1;}void PushDown(int rt){if(cover[rt]!=-1){cover[rt<<1]= cover[rt<<1|1]= cover[rt];XOR[rt<<1]= XOR[rt<<1|1]=0;cover[rt]=-1;}if(XOR[rt]){FXOR(rt<<1);FXOR(rt<<1|1);XOR[rt]=0;}}void update(char op,int L,int R,int l,int r,int rt){if(L <= l && r <= R){if(op =='U'){cover[rt]=1;XOR[rt]=0;}elseif(op =='D'){cover[rt]=0;XOR[rt]=0;}elseif(op =='C'|| op =='S'){FXOR(rt);}4041424344454647484950515253545556575859606162636465666768697071727374757677787980818283return;}PushDown(rt);int m =(l + r)>>1;if(L <= m) update(op , L , R , lson);elseif(op =='I'|| op =='C'){XOR[rt<<1]= cover[rt<<1]=0;}if(m < R) update(op , L , R , rson);elseif(op =='I'|| op =='C'){XOR[rt<<1|1]= cover[rt<<1|1]=0;}}void query(int l,int r,int rt){if(cover[rt]==1){for(int it = l ; it <= r ; it ++){hash[it]=true;}return;}elseif(cover[rt]==0)return;if(l == r)return;PushDown(rt);int m =(l + r)>>1;query(lson);query(rson);}int main(){cover[1]= XOR[1]=0;char op , l , r;int a , b;while( ~scanf("%c %c%d,%d%c\n",&op , &l , &a , &b , &r)){a <<=1 ,b <<=1;if(l =='(') a ++;if(r ==')') b --;if(a > b){if(op =='C'|| op =='I'){cover[1]= XOR[1]=0;}}else update(op , a , b , 0 , maxn , 1);}query(0 , maxn , 1);bool flag =false;int s =-1 , e;for(int i =0; i <= maxn ; i ++){84858687888990919293949596979899if(hash[i]){if(s ==-1) s = i;e = i;}else{if(s !=-1){if(flag)printf(" ");flag =true;printf("%c%d,%d%c",s&1?'(':'[' , s>>1 , (e+1)>>1 , e&1?')':']');s =-1;}}}if(!flag)printf("empty set");puts("");return0;}∙练习:o poj1436 Horizontally Visible Segmentso poj2991 Craneo Another LCISo Bracket Sequence∙区间合并这类题目会询问区间中满足条件的连续最长区间,所以PushUp的时候需要对左右儿子的区间进行合并o poj3667 Hotel题意:1 a:询问是不是有连续长度为a的空房间,有的话住进最左边2 a b:将[a,a+b-1]的房间清空思路:记录区间中最长的空房间线段树操作:update:区间替换query:询问满足条件的最左断点?View Code CPP1 2 3 4 5 6 7 8 9101112 #include <cstdio>#include <cstring>#include <cctype>#include <algorithm>usingnamespace std;#define lson l , m , rt << 1#define rson m + 1 , r , rt << 1 | 1constint maxn =55555;int lsum[maxn<<2] , rsum[maxn<<2] , msum[maxn<<2]; int cover[maxn<<2];1314151617181920212223242526272829303132333435363738394041424344454647484950515253545556 void PushDown(int rt,int m){if(cover[rt]!=-1){cover[rt<<1]= cover[rt<<1|1]= cover[rt];msum[rt<<1]= lsum[rt<<1]= rsum[rt<<1]= cover[rt]?0: m -(m >>1);msum[rt<<1|1]= lsum[rt<<1|1]= rsum[rt<<1|1]=cover[rt]?0:(m >>1);cover[rt]=-1;}}void PushUp(int rt,int m){lsum[rt]= lsum[rt<<1];rsum[rt]= rsum[rt<<1|1];if(lsum[rt]== m -(m >>1)) lsum[rt]+= lsum[rt<<1|1];if(rsum[rt]==(m >>1)) rsum[rt]+= rsum[rt<<1];msum[rt]= max(lsum[rt<<1|1]+ rsum[rt<<1] , max(msum[rt<<1] , msum[rt<<1|1]));}void build(int l,int r,int rt){msum[rt]= lsum[rt]= rsum[rt]= r - l +1;cover[rt]=-1;if(l == r)return;int m =(l + r)>>1;build(lson);build(rson);}void update(int L,int R,int c,int l,int r,int rt){if(L <= l && r <= R){msum[rt]= lsum[rt]= rsum[rt]= c ?0: r - l +1;cover[rt]= c;return;}PushDown(rt , r - l +1);int m =(l + r)>>1;if(L <= m) update(L , R , c , lson);if(m < R) update(L , R , c , rson);PushUp(rt , r - l +1);}int query(int w,int l,int r,int rt){if(l == r)return l;PushDown(rt , r - l +1);int m =(l + r)>>1;if(msum[rt<<1]>= w)return query(w , lson);elseif(rsum[rt<<1]+ lsum[rt<<1|1]>= w)return m - rsum[rt<<1]+1;57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 return query (w , rson );}int main (){ int n , m ;scanf ("%d%d",&n,&m ); build (1 , n , 1); while (m --){ int op , a , b ; scanf ("%d",&op ); if (op ==1){ scanf ("%d",&a ); if (msum [1]< a )puts ("0"); else { int p = query (a , 1 , n , 1); printf ("%d \n ",p );update (p , p + a -1 , 1 , 1 , n , 1);}}else { scanf ("%d%d",&a,&b );update (a , a + b -1 , 0 , 1 , n , 1);}} return 0;}∙ 练习:5 6 7 8 9101112131415161718192021222324252627282930313233343536373839404142434445464748 usingnamespace std;#define lson l , m , rt << 1#define rson m + 1 , r , rt << 1 | 1constint maxn =2222;int cnt[maxn <<2];double sum[maxn <<2];double X[maxn];struct Seg {double h , l , r;int s;Seg(){}Seg(double a,double b,double c,int d): l(a) , r(b) , h(c) , s(d){}bool operator <(const Seg &cmp)const{return h < cmp.h;}}ss[maxn];void PushUp(int rt,int l,int r){if(cnt[rt]) sum[rt]= X[r+1]- X[l];elseif(l == r) sum[rt]=0;else sum[rt]= sum[rt<<1]+ sum[rt<<1|1];}void update(int L,int R,int c,int l,int r,int rt){if(L <= l && r <= R){cnt[rt]+= c;PushUp(rt , l , r);return;}int m =(l + r)>>1;if(L <= m) update(L , R , c , lson);if(m < R) update(L , R , c , rson);PushUp(rt , l , r);}int Bin(double key,int n,double X[]){int l =0 , r = n -1;while(l <= r){int m =(l + r)>>1;if(X[m]== key)return m;if(X[m]< key) l = m +1;else r = m -1;}return-1;}int main(){495051525354555657585960616263646566676869707172737475767778int n , cas =1;while(~scanf("%d",&n)&& n){int m =0;while(n --){double a , b , c , d;scanf("%lf%lf%lf%lf",&a,&b,&c,&d);X[m]= a;ss[m++]= Seg(a , c , b , 1);X[m]= c;ss[m++]= Seg(a , c , d , -1);}sort(X , X + m);sort(ss , ss + m);int k =1;for(int i =1; i < m ; i ++){if(X[i]!= X[i-1]) X[k++]= X[i];}memset(cnt , 0 , sizeof(cnt));memset(sum , 0 , sizeof(sum));double ret =0;for(int i =0; i < m -1; i ++){int l = Bin(ss[i].l , k , X);int r = Bin(ss[i].r , k , X)-1;if(l <= r) update(l , r , ss[i].s , 0 , k -1, 1);ret += sum[1]*(ss[i+1].h- ss[i].h);}printf("Test case #%d\n Total explored area: %.2lf\n\n",cas++, ret);}return0;}o hdu1828 Picture题意:矩形周长并思路:与面积不同的地方是还要记录竖的边有几个(numseg记录),并且当边界重合的时候需要合并(用lbd和rbd表示边界来辅助)线段树操作:update:区间增减query:直接取根节点的值?View Code CPP1 2 3 4 5 6 7 8 #include <cstdio>#include <cstring>#include <cctype>#include <algorithm> usingnamespace std;#define lson l , m , rt << 1#define rson m + 1 , r , rt << 1 | 1910111213141516171819202122232425262728293031323334353637383940414243444546474849505152 constint maxn =22222;struct Seg{int l , r , h , s;Seg(){}Seg(int a,int b,int c,int d):l(a) , r(b) , h(c) , s(d){}bool operator <(const Seg &cmp)const{if(h == cmp.h)return s > cmp.s;return h < cmp.h;}}ss[maxn];bool lbd[maxn<<2] , rbd[maxn<<2];int numseg[maxn<<2];int cnt[maxn<<2];int len[maxn<<2];void PushUP(int rt,int l,int r){if(cnt[rt]){lbd[rt]= rbd[rt]=1;len[rt]= r - l +1;numseg[rt]=2;}elseif(l == r){len[rt]= numseg[rt]= lbd[rt]= rbd[rt]=0;}else{lbd[rt]= lbd[rt<<1];rbd[rt]= rbd[rt<<1|1];len[rt]= len[rt<<1]+ len[rt<<1|1];numseg[rt]= numseg[rt<<1]+ numseg[rt<<1|1];if(lbd[rt<<1|1]&& rbd[rt<<1]) numseg[rt]-=2;//两条线重合}}void update(int L,int R,int c,int l,int r,int rt){if(L <= l && r <= R){cnt[rt]+= c;PushUP(rt , l , r);return;}int m =(l + r)>>1;if(L <= m) update(L , R , c , lson);if(m < R) update(L , R , c , rson);PushUP(rt , l , r);}int main(){int n;while(~scanf("%d",&n)){int m =0;53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 6970 71 72 73int lbd =10000, rbd =-10000;for (int i =0; i < n ; i ++){int a , b , c , d ;scanf ("%d%d%d%d",&a,&b,&c,&d );lbd = min (lbd , a );rbd = max (rbd , c );ss [m ++]= Seg (a , c , b , 1);ss [m ++]= Seg (a , c , d , -1);}sort (ss , ss + m );int ret =0 , last =0;for (int i =0; i < m ; i ++){if (ss [i ].l < ss [i ].r ) update (ss [i ].l , ss [i ].r -1 , ss [i ].s , lbd , rbd -1 , 1);ret += numseg [1]*(ss [i +1].h - ss [i ].h );ret +=abs (len [1]- last );last = len [1];}printf ("%d \n ",ret );}return 0; } ∙ 练习。
浙师大acm教材
End;
writeln(x:6:2,operator,y:6:2,'=',n:6:2);
End.
4、念数字:编一个“念数字”的程序,它能让计算机完成以下工作:当你输入一个0至 99 之间的数
后,计算机就会用汉字拼音印出这个数的念结束。
例1:Input data:35
SAN SHI WU
例2:Input data:0
program Threebit;
var x,n,a,b,c:INTEGER;
BEGIN write('Input 3 bit nature data:'); readln(n);
IF (n>99) and (n<1000) then
begin a:=n DIV 100; {求百位数}
b:=(n-a*100) DIV 10;{求十位数}
while i mod a=0 do i:=i+b; lcm:=i; end;
瞿有甜整理
第2页
2006 年 9 月
浙江师范大学 ACM/ICPC 集训队――算法设计入门学习资料
第二节 编程入门题例
编程入门题(一)
1、位数对调:输入一个三位自然数,把这个数的百位与个位数对调,输出对
调后的数。例如:Input 3 bit natrue data:234
Case operator of
'+':n:=x+y;
{加法运算}
'-':n:=x-y;
{减法运算}
'*':n:=x*y;
{乘法运算}
'/':If y=0 then {除法运算}
浙江大学 acm程序设计竞赛 培训 线段树
[2,3][3,4]
[6,7] [7,8]
完全二叉树
• type • TreeNode = record • b, e: Integer; • cover: Integer; • end;
对应区间
插入算法
• • • • • • • • • • • • • • • • • procedure Insert(p, a, b: Integer); var 未被完全覆盖 m: Integer; begin if Tree[p].cover = 0 then 取中值 begin m := (Tree[p].b + Tree[p].e) div 2; 完全覆盖 if (a = Tree[p].b) and (b = Tree[p].e) then Tree[p].cover := 1 在左边 else if b <= m then Insert(p * 2, a, b) 在右边 else if a >= m then Insert(p * 2 + 1, a, b) else begin Insert(p * 2, a, m); Insert(p * 2 + 1, m, b); end; 二分 end; end;
分析
• 原先构造线段树的方法不再适用,但是我 们可以通过修改线段树的cover域的定义, 使得这道题也能用线段树来解。 • 定义cover如下:cover=-1表示该区间由多 种颜色组成。cover>=0表示该区间只有一 种单一的颜色cover。
插入算法
未被完全覆盖或者染色不同
• procedure Insert(p, l, r, a, b, c: Integer); • var 为什么? • m: Integer; 有可能越界吗? • begin • if Tree[p].cover <> c then • begin • m := (l + r) div 2; • if (a = l) and (b = r) then Tree[p].cover := c • else begin • if Tree[p].cover >= 0 then • begin • Tree[p * 2].cover := Tree[p].cover;
Acm竞赛常用算法与数据结构
时空复杂度的分析
• 时间复杂度的分析 • 空间复杂度的分析
14
函数增长和运行时间
引用刘汝佳 《序列和字 符串》
15
常见题型
•Dynamic Programming(动 动 态规划) 态规划 •Greedy(贪心 贪心) 贪心 •Complete Search(穷举 穷举) 穷举 •Flood Fill (种子填充 种子填充) 种子填充
16
常见题型
• Shortest Path (最短路径 最短路径) 最短路径 • Recursive Search Techniques (回溯) 回溯) 回溯 • Minimum Spanning Tree (最小 生成树) 生成树) • Knapsack(背包) (背包)
17
常见题型
•Computational Geometry(计算几何 计算几何) 计算几何 •Network Flow(网络流 网络流) 网络流 •Eulerian Path (欧拉回路 欧拉回路) 欧拉回路 •Two-Dimensional Convex Hull (二维凸包 二维凸包) 二维凸包
18பைடு நூலகம்
常见题型
•BigNums (大数 大数) 大数 •Heuristic Search(启发式 启发式 搜索) 搜索 •Approximate Search ( 近 似搜索) 似搜索 •Ad Hoc Problems(杂题 杂题) 杂题
19
20
枚举法
• 又叫穷举法,它利用了计算机计算 速度快且准确的特点,是最为朴素 和有效的一种算法。 • 不是办法的办法 • 但有时却是最好的办法
ACM竞赛 竞赛 常用算法 &数据结构
浙江大学微软技术俱乐部 彭鹏
浙江大学acm程序设计竞赛动态规划讲义
最
优
三
角
如果没有红色虚线的部分,或许你会
形
认为决策应该是枚举子多边形内的
划 分
两点连线,然后分成两个子多边形. 这显然是不行的,因为计算机已经无 法再表示分割出来的子多边形了(不
能用f[i,j]来表示了).
那么我们该如何决策呢?寻找定量!
显然可以发现,f[i,j]表示的子多边形
最
有一条边是在内部的(黑色虚线),而这 一条边在该子多边形内必定属于某个
end;
end;
动 规
有时候当前状态确定后,以前状 态就已经确定,则无需枚举.
的
要
诀
-
状
态
Tom是一个非常有创业精神的人,由于大
学学的是汽车制造专业,所以毕业后他
用有限的资金开了一家汽车零件加工厂,
专门为汽车制造商制造零件。由于资金
有限,他只能先购买一台加工机器。现
在他却遇到了麻烦,多家汽车制造商需
拦
每个导弹有一定的高度,当前状态
截 导
就是以第i个导弹为最后一个打的导
弹。以前状态就是在这个导弹以前 打的那个导弹。
弹
显然这是十分能够体现状态间的联
系的题目。
最
长
给出两个字符串序列。求出这 样的一个最长的公共子串:子
公
串中的每个字符都能在两个原
共
串中找到,而且每个字符的顺
子
序和原串中的顺序一致。
费情况下,每个车站的以前状态车站一
定是递增的序列.这里是只要O(N)的程
买
序:
车
for j:=1 to 3 do begin
票
k:=en-1; for i:=en downto be do
zoj浙江大学oj题目分类
搜索1002 Fire Net1004 Anagrams by Stack1005 Jugs1008 Gnome Tetravex1091 Knight Moves1101 Gamblers1204 Additive equations1221 Risk1230 Legendary Pokemon1249 Pushing Boxes1364 Machine Schedule1368 BOAT1406 Jungle Roads1411 Anniversary1453 Surround the Trees 凸包1516 Uncle Tom's Inherited Land1525 Air Raid1586 QS Network1602 Multiplication Puzzle dp1649 Rescue1671 Walking Ant1711 Sum It Up dfs1901 A Star not a Tree? 说他搜索可能有点争议(不管了)1940 Dungeon Master2100 Seeding2110 Tempter of the Bone2140 Bal难题&经典1003 Crashing Balloon1015 Fishing Net 完美图1144 Robbery1149 Dividing up1161 Gone Fishing1197 Sorting Slides1217 Eight1228 Farewell, My Friend1237 Fans and Gems1455 Schedule Problem1456 Minimum Transport Cost 图论最短路径要保存路径1492 Maximum Clique 图论经典算法--最大团1600 Market Place1605 One-way Traffic1568 WishingBone's Room Plan1742 Gap 至今一点想法都没有,难!!!1743 Concert Hall Scheduling1827 The Game of 31 博弈1855 Maze1903 Jogging Trails 中国邮路问题1909 Square 经典的dfs.2064 Bomberman - Just Search! 经典!2094 Max Angle 计算几何+博弈2125 Rocket Mania2126 Rocket Mania Plus2127 Zuma2128 Seven Seas2129 Mummy Maze2142 Light The Square (24道)dp1499 Increasing Sequences 经典题1107 FatMouse and Cheese 很好的一题1039 Number Game 没有完美解决的题,感觉可以直接以所有剩下的数作为状态DP 1227 Free Candies SRbGa的经典题1234 Chopsticks SRbGa的经典题……1554 Folding 推荐2059 The Twin Towers 推荐2097 Walking on a Chessboard 推荐1011 NTA 可用dp,也可以不用1013 Great Equipment1024 Calendar Game1027 Human Gene Functions1037 Gridland1052 Algernon's Noxious Emissions1058 Currency Exchange1076 Gene Assembly1092 Arbitrage1093 Monkey and Banana1094 Matrix Chain Multiplication1100 Mondriaan's Dream DP可以过,不过有组合公式1103 Hike on a Graph1134 Strategic Game1147 Formatting Text1148 The Game1161 Gone Fishing1180 Self Numbers1192 It's not a Bug, It's a Feature!1196 Fast Food1136 Multiple ,BFS1276 Optimal Array Multiplication Sequence1255 The Path1250 Always On the Run1213 Lumber Cutting1206 Win the Bonus1301 The New Villa1303 Jury Compromise 其实不是很难,但是很容易错1345 Best Deal1360 Radar Installation1396 The Umbrella Problem: 20541425 Crossed Matchings1438 Asteroids!1459 String Distance and Transform Process1462 Team Them Up!1556 Heroes Of Might And Magic1520 Duty Free Shop1524 Supermarket1536 Labyrinth1479 Dweep1245 Triangles 可用dp也可搜索1011 NTA 简单题1013 Great Equipment 简单题1024 Calendar Game 简单题1027 Human Gene Functions 简单题1037 Gridland简单题1052 Algernon\'\'s Noxious Emissions 简单题1409 Communication System 简单题,但是很容易看错~~~ 1425 Crossed Matchings简单题1438 Asteroids! 简单题1459 String Distance and Transform Process 简单题1462 Team Them Up! 简单题1556 Heroes Of Might And Magic 简单题,不过背景蛮有意思的……1520 Duty Free Shop 简单题1524 Supermarket 简单题1301 The New Villa 简单题1303 Jury Compromise 其实不是很难,但是很容易错,555……1345 Best Deal 简单题,但是也很容易错……555……1360 Radar Installation 简单题1396 The Umbrella Problem: 2054 简单题1058 Currency Exchange 简单题1076 Gene Assembly 简单题1092 Arbitrage 简单题1093 Monkey and Banana 简单题1094 Matrix Chain Multiplication 简单题1536 Labyrinth 简单题1100 Mondriaan\'\'s Dream 简单题,DP可以过,不过据说有复杂的组合公式1103 Hike on a Graph 简单题1134 Strategic Game 简单题1147 Formatting Text 简单题1148 The Game 简单题1161 Gone Fishing 简单题1180 Self Numbers 简单题1192 It\'\'s not a Bug, It\'\'s a Feature! 简单题1196 Fast Food 简单题1107 FatMouse and Cheese 简单题,不过题目描述有些混乱1136 Multiple 简单题,BFS1276 Optimal Array Multiplication Sequence 简单题1255 The Path 简单题1250 Always On the Run 简单题1213 Lumber Cutting 简单题1206 Win the Bonus 简单题1479 Dweep无聊题1587 UP 100 无聊题,DP应该可以……但是太烦了……没做……1066 Square Ice 无聊题,目前已知的O(nlogn)算法要用AVL……您有没有简单点的O(nlogn)的算法?1245 Triangles 无聊题1022 Parallel Expectations 经典题,想了n久,最后发现可以DP,相当好的一道题1499 Increasing Sequences 经典题{}1039 Number Game 没有完美解决的题,感觉可以直接以所有剩下的数作为状态DP,但是缺乏证明……1227 Free Candies SRbGa的经典题,我看了oibh上的解题报告才做出来的……1234 Chopsticks SRbGa的经典题……图论:1525 Air Raid 最小路径覆盖1500 Pre-Post-erous! 简单题1501 Knockout Tournament 简单题1508 Intervals 对您来说应该是简单题,但我想了n久……,差分限制系统1333 Galactic Import 简单题1304 Tin Cutter 简单题,但是似乎有空间复杂度为O(n)的算法1310 Robot 简单题1311 Network 简单题1344 A Mazing Problem 简单题1395 Door Man 简单题,欧拉回路1372 Networking 简单题1406 Jungle Roads 简单题1053 FDNY to the Rescue! 简单题1055 Oh, Those Achin\'\' Feet 不错的简单题1059 What\'\'s In a Name 二分图完美匹配1064 Roads Scholar 简单题1082 Stockbroker Grapevine 简单题1085 Alien Security 简单题,我觉得我当时的算法好巧妙1097 Code the Tree 简单题1060 Sorting It All Out 简单题,但是规模要是大些的话……1105 FatMouse\'\'s Tour 简单题1119 SPF 简单题1127 Roman Forts 简单题1140 Courses 简单题1157 A Plug for UNIX 蛮不错的简单题1203 Swordfish 简单题1221 Risk 简单题1197 Sorting Slides 简单题,匹配1268 Is It A Tree? 不错的题,图论1273 It\'\'s Ir-Resist-Able! 简单题,图论1298 Domino Effect 简单题,最长路1260 King 简单题,差分限制系统……1291 MPI Maelstrom 不错的题,最长路1266 Gossiping 简单题1285 Shipping Routes 无聊题,最短路1313 Gears on a Board 无聊题1502 Plugged In 无聊题,匹配应该可以,但是太烦了,没做……1568 WishingBone\'\'s Room Plan 无聊题,最大最小匹配,不过容易看错题~~~~~~~~1077 Genetic Combinations 无聊题,匹配1364 Machine Schedule 匹配1137 Girls and Boys 背诵题,匹配……1023 University Entrace Examination 经典题,但是和1576重复1576 Marriage is Stable 经典题,感人的背景,经典的算法……1249 Pushing Boxes 经典题,某人的论文写过,求割点和块+BFS可以在O(面积)的时间内做出来,没时间看论文,我用双重BFS过的1141 Closest Common Ancestors 没有完美解决,最简单的算法就能过,但要是规模大了……1084 Channel Allocation 尚未完美解决,我用搜索过的,不过是不是有更好的算法呢……?1231 Mysterious Mountain SRbGa的经典题……1232 Adventure of Super Mario SRbGa的经典题……数学:1007 Numerical Summation of a Series 简单题,还是蛮有意思的1045 HangOver简单题1049 I Think I Need a Houseboat 简单题1028 Flip and Shift 简单题,可以DP/BFS/……,但是实际上有数学方法可以直接判断出来1026 Modular multiplication of polynomials 简单题,感觉有比较简单的好算法,但想不出来1307 Packets 简单题,不过也蛮经典的……1312 Prime Cuts 简单题1334 Basically Speaking 简单题1337 Pi 简单题1342 Word Index 简单题1349 Four Quarters 简单题1350 The Drunk Jailer 简单题1352 Number Base Conversion 简单题1353 Unimodal Palindromic Decompositions 规模不大,所以是简单题……1354 Extended Lights Out 简单题1362 Game Prediction 简单题1365 Mileage Bank 简单题1382 A Simple Task 简单题1383 Binary Numbers 简单题1403 Safecracker 简单题1408 The Fun Number System 简单题1486 Color the Tree 简单题1487 Playing Cards 简单题1489 2^x mod n = 1 简单题,应该有好算法,枚举过的……1503 One Person "The Price is Right" 简单题,POI Eggs的翻版1512 Water Treatment Plants 简单题,组合计数1526 Big Number 简单题,不过O(1)和O(n)还是有区别的1529 Enigmatic Travel 简单题,不过个人感觉题目描述很令人费解1530 Find The Multiple 简单题1537 Playing with a Calculator 简单题1577 GCD & LCM 简单题,分区联赛的题……1005 Jugs 简单题1543 Stripies简单题1569 Partial Sums 简单题1062 Trees Made to Order 简单题1070 Bode Plot 简单题1073 Round and Round We Go 简单题1078 Palindrom Numbers 简单题1086 Octal Fractions 简单题1199 Point of Intersection 简单题1104 Leaps Tall Buildings 简单题1110 Dick and Jane 简单题1115 Digital Roots 简单题1113 u Calculate e 简单题1152 A Mathematical Curiosity 简单题1154 Niven Numbers 简单题1160 Biorhythms 简单题1163 The Staircases 简单题1177 K-Magic Number 简单题1184 Counterfeit Dollar 简单题1182 Keeps Going and Going and ... 简单题1284 Perfection 简单题1272 Numerically Speaking 简单题1269 Coconuts, Revisited 简单题1247 There\'\'s Treasure Everywhere! 简单题1241 Geometry Made Simple 简单题1202 Divide and Count 简单题1216 Deck 简单题1218 Ratio 简单题1261 Prime Land 简单题1212 Mountain Landscape 无聊题1410 Number Sequence 无聊题1401 Hilbert Curve Intersections 无聊题1331 Perfect Cubes 无聊题1322 Random Number 无聊题1535 Lucky Ticket 无聊题1539 Lot 无聊题1363 Chocolate 经典题……1366 Cash Machine 经典题!强烈推荐!1149 Dividing up 经典题,应该可以用1366的方法做,但似乎可以利用问题的特殊性用贪心+DP在O(1)的时间内做出来1222 Just the Facts 经典题,没有完美解决,据说可能有O(logn)的做法1475 Ranklist1572 Bracelet ~~~题义不明,感觉可能是判定欧拉回路的存在性1133 Smith Numbers 没有完美解决,数学1080 Direct Subtraction1229 Gift?! SRbGa的经典题……1238 Guess the Number SRbGa的经典题……1239 Hanoi Tower Troubles Again! SRbGa的经典题……字符串处理:1050 Start Up the Startup 简单题1315 Excuses, Excuses! 简单题1151 Word Reversal 简单题1170 String Matching 简单题1174 Skip Letter Code 不错的简单题1175 Word Process Machine 简单题1181 Word Amalgamation 简单题1038 T9 无聊题,单词树1330 DNA Translation 无聊题1335 Letter Sequence Analysis 无聊题1099 HTML 无聊题1243 URLs 无聊题1540 Censored! 经典题!强烈推荐!1511 Word Puzzles 后缀树模拟:1051 A New Growth Industry 简单题1300 Border 简单题1326 M*A*S*H 简单题1494 Climbing Worm 简单题1072 Microprocessor Simulation 简单题1098 Simple Computers 简单题1056 The Worm Turns 简单题1195 Blowing Fuses 简单题1189 Numbers That Count 简单题1144 Robbery 简单题1153 Tournament Seeding 简单题,但是直接计算好像不行,得模拟……1167 Trees on the Level 简单题1200 Mining 简单题1278 Pseudo-Random Numbers 简单题1257 Parking Lot 简单题1270 Nonstop Travel 简单题1207 The Knight, the Princess, and the Dragons 无聊题1169 Square Cipher 无聊题1176 Die and Chessboard 无聊题1178 Booklet Printing 无聊题1009 Enigma 无聊题,但是很容易错……1012 Mainframe 无聊题,但是很容易错……1324 Unix ls无聊题,输出格式没说清楚~~~~~~~1336 Mark-up 无聊题1277 Transferable Voting 无聊题1279 Cowculations无聊题1281 Hi-Q 无聊题1282 Call Forwarding 无聊题1065 Robots 变态题,太复杂啦~~~~~~~~~~~1208 Roll the Die! 变态题1388 Exchanges 经典题!强烈推荐!1236 Eat or Not to Eat? SRbGa的经典题……模拟几何:1575 Koch Curve 简单题1010 Area 简单题1565 Input 简单题1081 Points Within 简单题1165 Laser Lines 简单题1248 Video Surveillance 简单题,李彭煦的论文中写到过,好像是某年CTSC的……1299 Pendulum 简单题1090 The Circumference of the Circle 无聊题1271 Doing Windows 无聊题1280 Intersecting Lines 无聊题1296 Stars 经典变态题……1030 Farmland 变态题1041 Transmitters 变态题1158 Treasure Hunt 经典题1139 Rectangles 没有完美解决其它:1006 Do the Untwist 简单题1014 Operand 简单题1016 Parencodings 简单题1042 W\'\'s Cipher 简单题1047 Image Perimeters 简单题1514 Fake Tickets 简单题1029 Moving Tables 简单题,好像是线段树的经典题目之一,但是这题规模比较小,所以不必用。
ACM资料
最优比率生成树
0/1分数规划
度限制生成树
连通性问题
强大的DFS算法
无向图连通性
割点
割边
二连通分支
有向图连通性
强连通分支
2-SAT
最小点基
有向无环图
拓扑排序
有向无环图与动态规划的关系
二分图匹配问题
一般图问题与二分图问题的转换思路
组合数学
解决组合数学问题时常用的思想
逼近
递推 / 动态规划
概率问题
Polya定理
计算几何 / 解析几何
计算几何的核心:叉积 / 面积
解析几何的主力:复数
基本形
点
直线,线段
多边形
凸多边形 / 凸包
凸包算法的引进,卷包裹法
数论计算
求N的约数个数
求phi(N)
求约数和
快速数论变换
……
素数问题
概率判素算法
概率因子分解
数据结构
组织结构
二叉堆
左偏树
二项树
胜者树
跳跃表
样式图标
斜堆
reap
统计结构
树状数组
虚二叉树
线段树
8. 调用系统的qsort, 技巧很多,慢慢掌握.
9. 任意进制间的转换
第二阶段:
练习复杂一点,但也较常用的算法。
如:
1. 二分图匹配(匈牙利),最小路径覆盖
2. 网络流,最小费用流。
3. 线段树.
4. 并查集。
5. 熟悉动态规划的各个典型:LCS、最长递增子串、三角剖分、记忆化dp
浙江大学_acm程序设计竞赛_培训_线段树68页PPT
•
29、在一切能够接受法律支配的人类 的状态 中,哪 里没有 法律, 那里就 没有自 由。— —洛克
•
30、风俗可以造就法律,也可以废除 法律。 ——塞·约翰逊
线段树
6、最大的骄傲于最大的自卑都表示心灵的最软弱无力。——斯宾诺莎 7、自知之明是最难得的知识。——西班牙 8、勇气通往天堂,怯懦通往地狱。——塞内加 9、有时候读书是一种巧妙地避开思考的方法。——赫尔普斯 10、阅读一切好书如同和过去最杰出的人谈话。——笛卡儿
浙江大学_acm程序设计竞赛_培训_
•
26、我们像鹰一样,生来就是自由的 ,但是 为了生 存,我 们不得 不为自 己编织 一个笼 子,然 后把自 己关在 里面。 ——博 莱索
•
27、法律如果不讲道理,即使延续时 间再长 ,也还 是没有 制约力 的。— —爱·科 克
•
28、好法律是由坏风俗创造出来的。 ——马 克罗维 乌斯
ACM-线段树
ACM-线段树基础可以看上⾯这篇⽂章风格:maxn是题⽬给的最⼤区间,⽽节点数要开4倍,确切的说……lson和rson辨别表⽰结点的左孩⼦和右孩⼦。
PushUp(int rt)是把当前结点的信息更新到⽗节点PushDown(int rt)是把当前结点的信息更新给孩⼦结点。
rt表⽰当前⼦树的根(root),也就是当前所在的结点。
思想:对于每个⾮叶节点所标⽰的结点 [a,b],其做孩⼦表⽰的区间是[a,(a+b)/2],其右孩⼦表⽰[(a+b)/2,b].构造:离散化和线段树:题⽬:x轴上有若⼲个线段,求线段覆盖的总长度。
普通解法:设置坐标范围[min,max],初始化为0,然后每⼀段分别染⾊为1,最后统计1的个数,适⽤于线段数⽬少,区间范围⼩。
离散化的解法:离散化就是⼀⼀映射的关系,即将⼀个⼤坐标和⼩坐标进⾏⼀⼀映射,适⽤于线段数⽬少,区间范围⼤。
例如:[10000,22000],[30300,55000],[44000,60000],[55000,60000].第⼀步:排序 10000 22000 30300 44000 55000 60000第⼆部:编号 1 2 3 4 5 6第三部:⽤编号来代替原数,即⼩数代⼤数。
[10000,22000]~[1,2][30300,55000]~[3,5][44000,60000]~[4,6][55000,60000]~[5,6]然后再⽤⼩数进⾏普通解法的步骤,最后代换回去。
线段树的解法:线段树通过建⽴线段,将原来染⾊O(n)的复杂度减⼩到 log(n),适⽤于线段数⽬多,区间范围⼩的情况。
离散化的线段树:适⽤于线段数⽬多,区间范围⼤的情况。
构造:动态数据结构:struct node{node* left;node* right;……}静态全局数组模拟(完全⼆叉树):struct node{int left;int right;……}Tree[MAXN]线段树主要⽤四种⽤法单点更新:模板:单点增减,查询线段和struct node{int l,r,c;}T[MAXN*4];void PushUp(int rt){T[rt].c = T[rt<<1].c + T[(rt<<1)+1].c;}void build(int l,int r,int x){T[x].l = l;T[x].r = r;T[x].c = 0;if (l == r) return;int mid = (l+r)>>1;build(l,mid,x<<1);build(mid+1,r,(x<<1) + 1);}void update(int val,int l,int x){if(T[x].l == T[x].r && T[x].l == l){T[x].c += val;int mid = (T[x].l + T[x].r)>>1;if (l > mid){update(val,l,(x<<1) + 1);}else{update(val,l,x<<1);}PushUp(x);}int n,m,ans;void query(int l,int r,int x){if(T[x].l == l && T[x].r == r){ans += T[x].c;return;}int mid = (T[x].l + T[x].r)>>1;if (l > mid){query(l,r,(x<<1)+1);}else if(r<=mid){query(l,r,(x<<1));}else{query(l,mid,(x<<1));query(mid+1,r,(x<<1)+1);}}HDU 1166#include <iostream>#include <string>#include <cstring>#include <cstdlib>#include <cstdio>#include <cmath>#include <algorithm>#include <stack>#include <queue>#include <cctype>#include <vector>#include <iterator>#include <set>#include <map>#include <sstream>using namespace std;#define mem(a,b) memset(a,b,sizeof(a)) #define pf printf#define sf scanf#define spf sprintf#define pb push_back#define debug printf("!\n")#define MAXN 55555#define MAX(a,b) a>b?a:b#define blank pf("\n")#define LL long long#define ALL(x) x.begin(),x.end()#define INS(x) inserter(x,x.begin())#define pqueue priority_queue#define INF 0x3f3f3f3fstruct node{int l,r,c;}T[MAXN*4];void PushUp(int rt){T[rt].c = T[rt<<1].c + T[(rt<<1)+1].c; }void build(int l,int r,int x){T[x].l = l;T[x].r = r;T[x].c = 0;if (l == r) return;int mid = (l+r)>>1;build(l,mid,x<<1);build(mid+1,r,(x<<1) + 1);}void update(int val,int l,int x){if(T[x].l == T[x].r && T[x].l == l) {T[x].c += val;return;}int mid = (T[x].l + T[x].r)>>1;if (l > mid){update(val,l,(x<<1) + 1);}else{update(val,l,x<<1);}PushUp(x);}int n,m,ans;void query(int l,int r,int x){if(T[x].l == l && T[x].r == r){ans += T[x].c;return;}int mid = (T[x].l + T[x].r)>>1;if (l > mid){query(l,r,(x<<1)+1);}else if(r<=mid){query(l,r,(x<<1));}else{query(l,mid,(x<<1));query(mid+1,r,(x<<1)+1);}}int main(){int t,i,kase=1;char d[10];sf("%d",&t);while(t--){mem(T,0);pf("Case %d:\n",kase++);sf("%d",&n);build(1,n,1);for(i=1;i<=n;i++){int tmp;sf("%d",&tmp);update(tmp,i,1);}while (sf("%s",d) != EOF){if (d[0] == 'E') break;int x, y;sf("%d%d", &x, &y);if (d[0] == 'Q'){ans = 0;}if (d[0] == 'S') update(-y,x,1);if (d[0] == 'A') update(y,x,1);}}return0;}单点替换,查询线段最⾼模板:struct node{int l,r,c;}T[MAXN*4];void PushUp(int rt){T[rt].c = max(T[rt<<1].c,T[(rt<<1)+1].c); }void build(int l,int r,int x){T[x].l = l;T[x].r = r;T[x].c = 0;if (l == r) return;int mid = (l+r)>>1;build(l,mid,x<<1);build(mid+1,r,(x<<1) + 1);}void update(int val,int l,int x){if(T[x].l == T[x].r && T[x].l == l){T[x].c = val;return;}int mid = (T[x].l + T[x].r)>>1;if (l > mid){update(val,l,(x<<1) + 1);}else{update(val,l,x<<1);}PushUp(x);}int n,m,ans;void query(int l,int r,int x){if(T[x].l == l && T[x].r == r){ans = max(ans,T[x].c);return;}int mid = (T[x].l + T[x].r)>>1;if (l > mid){query(l,r,(x<<1)+1);}else if(r<=mid){query(l,r,(x<<1));}else{query(l,mid,(x<<1));query(mid+1,r,(x<<1)+1);}}hdu 1754这边要注意,输⼊字符不要⽤%c,会导致⼀些难以预料的问题#include <iostream>#include <string>#include <cstring>#include <cstdlib>#include <cstdio>#include <cmath>#include <algorithm>#include <stack>#include <queue>#include <cctype>#include <vector>#include <iterator>#include <set>#include <map>#include <sstream>using namespace std;#define mem(a,b) memset(a,b,sizeof(a))#define pf printf#define sf scanf#define spf sprintf#define pb push_back#define debug printf("!\n")#define MAXN 200005#define MAX(a,b) a>b?a:b#define blank pf("\n")#define LL long long#define ALL(x) x.begin(),x.end()#define INS(x) inserter(x,x.begin())#define pqueue priority_queue#define INF 0x3f3f3f3fstruct node{int l,r,c;}T[MAXN*4];void PushUp(int rt){T[rt].c = max(T[rt<<1].c,T[(rt<<1)+1].c);}void build(int l,int r,int x){T[x].l = l;T[x].r = r;T[x].c = 0;if (l == r) return;int mid = (l+r)>>1;build(l,mid,x<<1);build(mid+1,r,(x<<1) + 1);}void update(int val,int l,int x){if(T[x].l == T[x].r && T[x].l == l){T[x].c = val;return;}int mid = (T[x].l + T[x].r)>>1;if (l > mid){update(val,l,(x<<1) + 1);}else{update(val,l,x<<1);}PushUp(x);}int n,m,ans;void query(int l,int r,int x){if(T[x].l == l && T[x].r == r){return;}int mid = (T[x].l + T[x].r)>>1;if (l > mid){query(l,r,(x<<1)+1);}else if(r<=mid){query(l,r,(x<<1));}else{query(l,mid,(x<<1));query(mid+1,r,(x<<1)+1);}}int main(){int t,i,kase=1;while(sf("%d%d",&n,&m)==2){build(1,n,1);for(i=1;i<=n;i++){int tmp;sf("%d",&tmp);update(tmp,i,1);}while (m--){int x,y;char d[2];sf("%s %d %d",d,&x, &y);//pf("%s %d %d\n",d,x,y);if (d[0] == 'Q'){ans = 0;query(x,y,1);pf("%d\n",ans);}if (d[0] == 'U') update(y,x,1);}}return0;}成段更新(通常这对初学者来说是⼀道坎),需要⽤到延迟标记(或者说懒惰标记),简单来说就是每次更新的时候不要更新到底,⽤延迟标记使得更新延迟到下次需要更新or询问到的时候区间替换,求总和数组要开4倍才够第⼀种思路,标记模板:struct node{int l,r,c,f;}T[MAXN<<2];void PushUp(int rt){T[rt].c = T[rt<<1].c + T[(rt<<1)+1].c;//pf("%d %d\n",rt,T[rt].c);}{if(T[rt].f){T[rt<<1].f = T[(rt<<1) + 1].f = T[rt].f;T[rt<<1].c = T[rt].f * (m-(m>>1));T[(rt<<1)+1].c = T[rt].f * (m>>1);T[rt].f = 0;}}void build(int l,int r,int x){T[x].l = l;T[x].r = r;T[x].c = 1;T[x].f = 0;if (l == r) return;int mid = (l+r)>>1;build(l,mid,x<<1);build(mid+1,r,(x<<1) + 1);PushUp(x);}void update(int val,int L,int R,int l,int r,int x){if(L <= l && r <= R){T[x].f = val;T[x].c = val*(r-l+1);//pf("%d %d %d\n",T[x].c,l,r);return;}PushDown(x,r-l+1);//pf("%d %d %d %d %d %d\n",val,L,R,l,r,x);int mid = (l + r)>>1;if (L <= mid){update(val,L,R,l,mid,x<<1);}if(R > mid){update(val,L,R,mid+1,r,x<<1|1);}PushUp(x);}第⼆种思路,杂⾊struct node{int l,r,c;}T[MAXN<<2];void PushUp(int rt){T[rt].c = T[rt<<1].c + T[(rt<<1)+1].c;}void PushDown(int rt){if(T[rt].c != -1)//如果该区间只有⼀种颜⾊{T[rt<<1].c = T[rt<<1|1].c = T[rt].c;//由于后⾯必定对⼦树操作,所以更新⼦树的值等于⽗亲的值 T[rt].c = -1;//由于该区域颜⾊与修改不同,⽽且不是给定区域,所以该区域必定为杂⾊}}void build(int l,int r,int x){T[x].l = l;T[x].r = r;T[x].c = 1;if (l == r) return;int mid = (l+r)>>1;build(l,mid,x<<1);build(mid+1,r,(x<<1) + 1);}void update(int val,int L,int R,int x)if(T[x].c == val) return;//相同则不⽤修改了if(T[x].l == L && T[x].r == R)//找到了区间,直接更新{T[x].c = val;return;}PushDown(x);//⽗区间为杂⾊时对所有⼦节点进⾏操作int mid = (T[x].l + T[x].r)>>1;if(L>mid)update(val,L,R,x<<1|1);else if(R<=mid)update(val,L,R,x<<1);else{update(val,L,mid,x<<1);update(val,mid+1,R,x<<1|1);}}hdu 1698这⾥链接的其实不对,要求总和,所以每个点不能初始化为1 #include <iostream>#include <string>#include <cstring>#include <cstdlib>#include <cstdio>#include <cmath>#include <algorithm>#include <stack>#include <queue>#include <cctype>#include <vector>#include <iterator>#include <set>#include <map>#include <sstream>using namespace std;#define mem(a,b) memset(a,b,sizeof(a))#define pf printf#define sf scanf#define spf sprintf#define pb push_back#define debug printf("!\n")#define MAXN 100000 + 5#define MAX(a,b) a>b?a:b#define blank pf("\n")#define LL long long#define ALL(x) x.begin(),x.end()#define INS(x) inserter(x,x.begin())#define pqueue priority_queue#define INF 0x3f3f3f3fstruct node{int l,r,c,f;}T[MAXN<<2];void PushUp(int rt){T[rt].c = T[rt<<1].c + T[(rt<<1)+1].c;//pf("%d %d\n",rt,T[rt].c);}void PushDown(int rt,int m){if(T[rt].f){T[rt<<1].f = T[(rt<<1) + 1].f = T[rt].f;T[rt<<1].c = T[rt].f * (m-(m>>1));T[(rt<<1)+1].c = T[rt].f * (m>>1);T[rt].f = 0;}void build(int l,int r,int x){T[x].l = l;T[x].r = r;T[x].c = 1;T[x].f = 0;if (l == r) return;int mid = (l+r)>>1;build(l,mid,x<<1);build(mid+1,r,(x<<1) + 1);PushUp(x);}void update(int val,int L,int R,int l,int r,int x){if(L <= l && r <= R){T[x].f = val;T[x].c = val*(r-l+1);//pf("%d %d %d\n",T[x].c,l,r);return;}PushDown(x,r-l+1);//pf("%d %d %d %d %d %d\n",val,L,R,l,r,x);int mid = (l + r)>>1;if (L <= mid){update(val,L,R,l,mid,x<<1);}if(R > mid){update(val,L,R,mid+1,r,x<<1|1);}PushUp(x);}int n,m,ans;void query(int l,int r,int x){if(T[x].l == l && T[x].r == r){ans += T[x].c;return;}int mid = (T[x].l + T[x].r)>>1;if (l > mid){query(l,r,(x<<1)+1);}else if(r<=mid){query(l,r,(x<<1));}else{query(l,mid,(x<<1));query(mid+1,r,(x<<1)+1);}}int a[MAXN];int main(){int t,i,kase=1;sf("%d",&t);while(t--){sf("%d",&n);build(1,n,1);sf("%d",&m);for(i=1;i<=m;i++){int x,y,z;sf("%d%d%d",&x,&y,&z);update(z,x,y,1,n,1);}pf("Case %d: The total value of the hook is %d.\n",kase++,T[1].c);return0;}区间增减,区间求和模板:struct node{LL l,r,c,f;}T[MAXN<<2];void PushUp(int rt){T[rt].c = T[rt<<1].c + T[(rt<<1)+1].c;//pf("%d %d\n",rt,T[rt].c);}void PushDown(int rt,int m){if(T[rt].f){T[rt<<1].f += T[rt].f;T[(rt<<1) + 1].f += T[rt].f;T[rt<<1].c += T[rt].f * (m-(m>>1));T[(rt<<1)+1].c += T[rt].f * (m>>1);T[rt].f = 0;}}void build(int l,int r,int x){T[x].l = l;T[x].r = r;T[x].f = 0;T[x].c = 0;if(l==r) return;int mid = (l+r)>>1;build(l,mid,x<<1);build(mid+1,r,(x<<1) + 1);}void update(int val,int L,int R,int l,int r,int x){if(L <= l && r <= R){T[x].f += val;T[x].c += val*(r-l+1);//pf("%d %d %d\n",T[x].c,l,r);return;}PushDown(x,r-l+1);//pf("%d %d %d %d %d %d\n",val,L,R,l,r,x);int mid = (l + r)>>1;if (L <= mid){update(val,L,R,l,mid,x<<1);}if(R > mid){update(val,L,R,mid+1,r,x<<1|1);}PushUp(x);}LL ans;int n,m;void query(int L,int R,int l,int r,int x){if(L <= l && r <= R){ans += T[x].c;return;}PushDown(x,r-l+1);int mid = (l + r)>>1;if(L <= mid) query(L,R,l,mid,x<<1);if(R > mid) query(L,R,mid+1,r,x<<1|1); PushUp(x);}poj 3468#include <iostream>#include <string>#include <cstring>#include <cstdlib>#include <cstdio>#include <cmath>#include <algorithm>#include <stack>#include <queue>#include <cctype>#include <vector>#include <iterator>#include <set>#include <map>#include <sstream>using namespace std;#define mem(a,b) memset(a,b,sizeof(a)) #define pf printf#define sf scanf#define spf sprintf#define pb push_back#define debug printf("!\n")#define MAXN 111111 + 5#define MAX(a,b) a>b?a:b#define blank pf("\n")#define LL long long#define ALL(x) x.begin(),x.end()#define INS(x) inserter(x,x.begin())#define pqueue priority_queue#define INF 0x3f3f3f3fstruct node{LL l,r,c,f;}T[MAXN<<2];void PushUp(int rt){T[rt].c = T[rt<<1].c + T[(rt<<1)+1].c;//pf("%d %d\n",rt,T[rt].c);}void PushDown(int rt,int m){if(T[rt].f){T[rt<<1].f += T[rt].f;T[(rt<<1) + 1].f += T[rt].f;T[rt<<1].c += T[rt].f * (m-(m>>1));T[(rt<<1)+1].c += T[rt].f * (m>>1);T[rt].f = 0;}}void build(int l,int r,int x){T[x].l = l;T[x].r = r;T[x].f = 0;if(l==r){scanf("%I64d",&T[x].c);return;}int mid = (l+r)>>1;build(l,mid,x<<1);build(mid+1,r,(x<<1) + 1);PushUp(x);}void update(int val,int L,int R,int l,int r,int x) {if(L <= l && r <= R){T[x].f += val;T[x].c += val*(r-l+1);//pf("%d %d %d\n",T[x].c,l,r);return;}PushDown(x,r-l+1);//pf("%d %d %d %d %d %d\n",val,L,R,l,r,x); int mid = (l + r)>>1;if (L <= mid){update(val,L,R,l,mid,x<<1);}if(R > mid){update(val,L,R,mid+1,r,x<<1|1);}PushUp(x);}LL ans;int n,m;void query(int L,int R,int l,int r,int x){if(L <= l && r <= R){ans += T[x].c;return;}PushDown(x,r-l+1);int mid = (l + r)>>1;if(L <= mid) query(L,R,l,mid,x<<1);if(R > mid) query(L,R,mid+1,r,x<<1|1);}int main(){int t,i,kase=1;while(~sf("%d%d",&n,&m)){build(1,n,1);/*for(i=1;i<=n;i++){int tmp;sf("%d",&tmp);update(tmp,i,i,1,n,1);}*/for(i=1;i<=m;i++){int x,y,z;char s[2];sf("%s",s);if(s[0]=='Q'){ans = 0;sf("%d%d",&x,&y);query(x,y,1,n,1);pf("%I64d\n",ans);}else{sf("%d%d%d",&x,&y,&z);update(z,x,y,1,n,1);}}}return0;}。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
统计算法
function Count(p: Integer): Integer; begin 被完全覆盖 if Tree[p].cover = 1 then 是单位区间 Count := Tree[p].e – Tree[p].b else if Tree[p].e – Tree[p].b = 1 then Count := 0 else Count := Count(p * 2) + Count(p * 2 + 1); end;
[2,3][3,4]
[6,7] [7,8]
完全二叉树
type TreeNode = record b, e: Integer; cover: Integer; end;
对应区间
插入算法
procedure Insert(p, a, b: Integer); var 未被完全覆盖 m: Integer; begin if Tree[p].cover = 0 then 取中值 begin m := (Tree[p].b + Tree[p].e) div 2; 完全覆盖 if (a = Tree[p].b) and (b = Tree[p].e) then Tree[p].cover := 1 在左边 else if b <= m then Insert(p * 2, a, b) 在右边 else if a >= m then Insert(p * 2 + 1, a, b) else begin Insert(p * 2, a, m); Insert(p * 2 + 1, m, b); end; 二分 end; end;
二分递归求解
事实上,我们也可以不在每个节点中保存 其表示范围,而是在递归调用时增加两个 参数来加以表示.
另一种定义
type TreeNode = record cover: Integer; end;
插入算法
procedure Insert(p, l, r, a, b: Integer); var m: Integer; Tree[p].b换成了 , 换成了l, 换成了 begin Tree[p].e换成了 ,递归 换成了r, 换成了 if Tree[p].cover = 0 then 时需要多加两个参数, 时需要多加两个参数, begin 其余都一样 m := (l + r) div 2; if (a = l) and (b = r) then Tree[p].cover := 1 else if b <= m then Insert(p * 2, l, m, a, b) else if a >= m then Insert(p * 2 + 1, m, r, a, b) else begin Insert(p * 2, l, m, a, m); Insert(p * 2 + 1, m, r, m, b); end; end; end;
插入算法
未被完全覆盖或者染色不同
Tree[p * 2 + 1].cover := Tree[p].cover; Tree[p].cover := -1; 为什么? 为什么? end; 有可能越界吗? 有可能越界吗? if b <= m then Insert(p * 2, l, m, a, b, c) else if a >= m then Insert(p * 2 + 1, m, r, a, b, c) else begin Insert(p * 2, l, m, a, m, c); Insert(p * 2 + 1, m, r, m, b, c); end; end; end; end;
缺点
此方法的时间复杂度决定于线段数的平方. 对于线段数较多的情况此方法效率太低.
使用线段树的做法
给线段树每个节点增加一个域cover. cover=1表示该结点所对应的区间被完全覆盖, cover=0表示该结点所对应的区间未被完全覆 盖.
加入[4,6] 加入[3,5] 加入[1,2] [1,6,0] [1,3,0] [1,2,1] [1,2,0] [2,3,0] [3,4,0] [3,4,1] [3,6,0] [4,6,1] [4,6,0] [4,5,0] [4,5,1] [5,6,0]
统计算法
使用一个数组Flag,初始化为0.遍历线段树, 对于每种颜色c对Flag[c]赋值1.最后统计 Flag中1的个数即可.(注意颜色0应该排除 在外,可以在最后减1)
统计算法
procedure Count(p, l, r: Integer); begin if Tree[p].cover >= 0 then Flag[Tree[p].cover] := 1 else if r – l > 1 then begin Count(p * 2, l, (l + r) div 2); Count(p * 2 + 1, (l + r) div 2, r); end; end;
示例
[10000,22000] [30300,55000] [44000,60000] [55000,60000] 排序得10000,22000,30300,44000,55000,60000 对应得1 [1,2] ,2 ,3 [3,5] ,4 ,5 [4,6] ,6 [5,6]
示例
初始情况 [1,2] [3,5] [4,6] [5,6]
非底色,则总数减 非底色,则总数减1
统计算法
最左边的颜色
end 最右边的颜色 else if r – l > 1 then 最左颜色=最右颜色 最右颜色=本身 最左颜色 最右颜色 本身 begin 非底色则统计数加1 非底色则统计数加 result := Count(p * 2, l, (l + r) div 2, lc, tl) + Count(p * 2 + 1, (l + r) div 2, r, tr, rc); if (tl = tc) and (tl > 0) then result := result - 1; Count := result; end; 连接处颜色相同并且 end; 非底色,则总数减1 非底色,则总数减
分析
原先构造线段树的方法不再适用,但是我 们可以通过修改线段树的cover域的定义, 使得这道题也能用线段树来解. 定义cover如下:cover=-1表示该区间由多 种颜色组成.cover>=0表示该区间只有一 种单一的颜色cover.
插入算法
未被完全覆盖或者染色不同
procedure Insert(p, l, r, a, b, c: Integer); var 为什么? 为什么? m: Integer; 有可能越界吗? 有可能越界吗? begin if Tree[p].cover <> c then begin m := (l + r) div 2; if (a = l) and (b = r) then Tree[p].cover := c else begin if Tree[p].cover >= 0 then begin Tree[p * 2].cover := Tree[p].cover;
线段树
浙江大学 acm校队
线段树
在一类问题中,我们需要经常处理可以映射 在一个坐标轴上的一些固定线段,例如说映 射在OX轴上的线段.由于线段是可以互相覆 盖的,有时需要动态地取线段的并,例如取 得并区间的总长度,或者并区间的个数等等. 一个线段是对应于一个区间的,因此线段树 也可以叫做区间树.
线段树的构造思想
程序实现
线段树的数据结构表示
1,动态数据结构 2,完全二叉树
动态数据结构
type pNode = ^TreeNode; TreeNode = record 对应区间 b, e: Integer; 左右孩子 l, r: pNode; cover: Integer; end;
完全二叉树
[1,9] [1,5] [1,3] [1,2] [3,5] [4,5] [5,7] [5,6] [5,9] [7,9] [8,9]
线段树是一棵二叉树,树中的每一个结点表 示了一个区间[a,b].每一个叶子节点表示了 一个单位区间.对于每一个非叶结点所表示 的结点[a,b],其左儿子表示的区间为 [a,(a+b)/2],右儿子表示的区间为[(a+b)/2,b].
[1,10] [1,5] [1,3] [1,2] [3,5] [4,5] [5,7] [5,6] [6,7] [5,10] [7,10] [7,8] [8,10]
例2
桌子上零散地放着若干 个盒子,桌子的后方是 一堵墙.如右图所示. 问从桌子前方可以看到 多少个盒子?假设人站 得足够远.
Wall
分析
可以这样来看这道题:x轴上有若干条不同 线段,将它们依次染上不同的颜色,问最 后能看到多少种不同的颜色?(后染的颜 色会覆盖原先的颜色) 我们可以这样规定:x轴初始是颜色0,第 一条线段染颜色1,第二条线段染颜色2, 以此类推.
[2,3] [3,4]
[8,9]
[9,10]
线段树的运用
线段树的每个节点上往往都增加了一些其他 的域.在这些域中保存了某种动态维护的信 息,视不同情况而定.这些域使得线段树具 有极大的灵活性,可以适应不同的需求.
例1
Light
桌子上零散地放着若干 个盒子,桌子的后方是 一堵墙.如右图所示. 现在从桌子的前方射来 一束平行光, 把盒子的 影子投射到了墙上.问 影子的总宽度是多少?
例3
把例2稍加改动,规定:线段的颜色可以相同. 连续的相同颜色被视作一段.问x轴被分成多 少段.
分析
仍然定义cover如下:cover=-1表示该区间 由多种颜色组成.cover>=0表示该区间只 有一种单一的颜色cover.