浙江大学_acm程序设计竞赛_培训_线段树
- 格式:ppt
- 大小:454.00 KB
- 文档页数:66
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。
线段树之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;支持查找一个结点或线段是否被覆盖。
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培训大纲基础内容:数据结构——》搜索——》图论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++的同学进行基础的讲解。
【完全版】线段树很早前写的那篇线段树专辑至今一直是本博客阅读点击量最大的一片文章,当时觉得挺自豪的,还去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; } ∙ 练习。
搜索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-线段树基础可以看上⾯这篇⽂章风格: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;}。