浙江大学 acm程序设计竞赛 培训 线段树共66页文档
浙江大学 acm程序设计竞赛 培训 线段树共68页文档
61、辍学如磨刀之石,不见其损,日 有所亏 。 62、奇文共欣赞,疑义相与析。
63、暧暧远人村,依依墟里烟,狗吠 深巷中 ,鸡鸣 桑树颠 。 64、一生复能几,倏如流电惊。 65、少无适俗韵,性本爱丘山。
61、奢侈是舒适的,否则就不是奢侈 。——CocoCha nel 62、少而好学,如日出之阳;壮而好学 ,如日 中之光 ;志而 好学, 如炳烛 之光。 ——刘 向 63、三军可夺帅也,匹夫不可夺志也。 ——孔 丘 64、人生就是学校。在那里,与其说好 的教师 是幸福 ,不如 说好的 教师是 不幸。 ——海 贝尔 65、接受挑战,就可以享受胜利的喜悦 。——杰纳勒 尔·乔治·S·巴顿
谢谢!
ห้องสมุดไป่ตู้
杭电acm初学者课件
2006年5月,浙江省第二届“舜宇”杯大学生程序设计大 赛
2006年11~12月,第31届ACM首尔、北京、上海和西安赛 区比赛 今年…
9 2019/5/16
预期赛事(今后每年)
3~4月,举行校内大赛(暨选拔赛) 5月,参加浙江省大学生程序设计大赛 11月,参加ACM/ICPC亚洲区比赛(至 少参加4~5个赛区的比赛) 另外,每学期至少有三次月赛以及适当 的练习赛
26 2019/5/16
Hdoj_1089源代码:
#include <stdio.h> int main() {
int a,b;
while(scanf("%d %d",&a, &b) != EOF) printf("%d\n",a+b);
}
27 2019/5/16
本类输入解决方案:
C语法: while(scanf("%d %d",&a, &b) != EOF) { .... } C++语法: while( cin >> a >> b ) { .... }
4 2019/5/16
我们说的“ACM” 是什么?
5 2019/5/16
ACM/ICPC:
ACM主办的国际大学生程序设计竞赛 (International Collegiate Programming Contest),简称 ACM / ICPC,自从1977年开始至今已经连续举 办31届。其宗旨是提供一个让大学生向IT界展 示自己分析问题和解决问题的能力的绝好机会, 让下一代IT天才可以接触到其今后工作中将要 用到的各种软件。 现在,ACM / ICPC已成为世界各国大学生中最 具影响力的国际计算机赛事。(非官方)
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简单讲解 1
Lecture I 比赛经验与编程技巧
– 得到右数第k位值 – 把右数第k位置1 – 把右数第k位取反 – 把最右边的1置0 – 把最右边的0置1 – 判断奇偶(最低位) (x >> k) & 1 x | (1 << k) x ^ (1 << k) x & (x – 1) x | (x + 1) x&1
枚举所有选取方式
• 枚举n个数中选一些的方式
熟悉比赛环境
• 熟悉交题、查看返回信息的方法 • 熟悉Runs中的Search功能 • 打印功能
比赛进行时
比赛策略
• 寻找简单题 • 看题、交流题意 • 观察气球、ranklist,跟风 • 打印、纸上调试 • 学会放弃 • 全面开花 vs 孤注一掷
输入输出
• 几种输入输出要求 • 负数和-1的区别 • 行内拆分(使用stringstream) • 输出格式,如时间”%02d:%02d:%02d”
• 申请新节点,并加到p节点后
– next[p] = ind++;
Standard C++ Library
C++风格头文件
• #include • #include • #include • #include • #include • #include • #include <iostream> <cstdio> <string> <cstring> <cmath> <vector> <algorithm>
浙大ACM简单讲解
• dp[2] = dp[1] + 1 + 1 = 4
• dp[3] = min{ dp[1] + 1 * 2 + 1, dp[2] + 1 + 1}
•
=5
G Islands
• 给定最多100个点的有向图,问有多少种加 边的方式,可以让最后整个图只由一些环 构成,没有多余的边。一个环至少要两个 点。
Lecture III 赛题解析
杭航@ZJU mailto:Hang.Hang.ZJU@
QQ:54621399
Part I The 10th ZJU Programming Contest
概述
• A Clock
472/614
• B CAPTCHA
87/399
• C Runaway t Bulb
• 三分法 • 求单峰函数在(x1,x2)上的极值 • 令a=(x2-x1)/3 + x1 • 令b=(x2-x1)/3 *2 + x1 • 如果f(a)>f(b),则用b更新x2 • 如果f(a)<f(b),则用a更新x1 • 每次把区间缩小成原来的2/3,最后收敛到
B Light Bulb
• 方法一:数学解法,列出函数式子,求导 解决
• 方法二:猜测L是关于某个参数的单峰函数, 可以采用三分法。
B Light Bulb
• 二分法 • 求单调函数在(x1,x2)上的零点 • 令x=(x1+x1)/2 • 如果f(x)和f(x1)同号,则用x更新x1 • 如果f(x)和f(x2)同号,则用x更新x2 • 每次把区间缩小成原来的1/2,最后收敛到
H Break Out
• 预处理后,变成了一个背包问题,背包的 容量最多为200,有最多200个物品,每个 物品不同容量的时候有不同的价值,求使 得总价值最高的方案。
ACM培训资料
ACM培训资料目录第一篇入门篇 (3)第1章新手入门 (5)1ACM国际大学生程序设计竞赛简介 (5)2ACM竞赛需要的知识 (8)3团队配合 (14)4练习、练习、再练习 (15)5对新手的一些建议 (16)第2章C++语言介绍 (22)1C++简介 (22)2变量 (23)3C++数据类型 (25)4C++操作符 (30)5数组 (35)6字符数组 (38)7字串操作函数 (41)8过程控制 (45)9C++中的函数 (54)10函数规则 (59)第3章STL简介 (61)1泛型程序设计 (61)2STL 的组成 (67)第二篇算法篇 (102)第1章基本算法 (103)1算法初步 (103)2分治算法 (115)3搜索算法 (124)4贪婪算法 (135)第2章进阶算法 (165)1数论基础 (165)2图论算法 (180)3计算几何基础 (222)第三篇实践篇 (246)第1章《多边形》 (247)第2章《灌溉问题》 (255)第3章《L GAME》 (263)第4章《NUMBER》解题报告 (271)第5章《J OBS》解题报告 (275)第6章《包裹运送》 (283)第7章《桶的摆放》 (290)第一篇入门篇练就坚实的基础,总有一天……我们可以草木皆兵!第1章新手入门1ACM国际大学生程序设计竞赛简介1.1背景与历史1970年在美国TexasA&M大学举办了首次区域竞赛,从而拉开了国际大学生程序设计竞赛的序幕。
1977年,该项竞赛被分为两个级别,即区域赛和总决赛,这便是现代ACM竞赛的开始。
在亚洲、美国、欧洲、太平洋地区均设有区域赛点。
1995至1996年,来自世界各地的一千多支高校的代表队参加了ACM区域竞赛。
ACM 大学生程序设计竞赛由美国计算机协会(ACM)举办,旨在向全世界的大学生提供一个展示和锻炼其解决问题和运用计算机能力的机会,现已成为全世界范围内历史最悠久、规模最大的大学生程序设计竞赛。
ACM 程序设计竞赛入门:第4讲 简单数据结构
2020/12/10
7
1. 并查集
初始状态 : {1} {2} {3} {4} {5} {6} {7} {8} {9}
输入关系 分离集合
(2,4)
{2,4}
•最后我们得到3 个集合{1,2,3,4},
(5,7) (1,3) (8,9) (1,2) (5,6)
{2,4} {5,7} {1,3} {2,4} {5,7} {1,3} {2,4} {5,7} {8,9} {1,2,3,4} {5,7} {8,9} {1,2,3,4} {5,6,7} {8,9}
两个强盗是同一团伙的条件是当且仅当他们是朋 友。现在给你一些关于强盗们的信息,问你最多 有多少个强盗团伙。
2020/12/10
3
1. 并查集
1.1 引例
输入格式 (Input Format):
输入的第一行是一个整数N(2<=N<=1000),表 示强盗的个数(从1编号到N)。 第二行 M(1<=M<=5000),表示关于强盗的信息条数。 以下M行,每行可能是F p q或是E p q(1<=p q<=N),F表示p和q是朋友,E表示p和q是敌人 。输入数据保证不会产生信息的矛盾。
第四讲 简单数据结构
2020/12/10
1
主要内容
并查集 树状数组 线段树
2020/12/10
2
1. 并查集
1.1 引例
题目描述:
1920年的芝加哥,出现了一群强盗。如果两个强 盗遇上了,那么他们要么是朋友,要么是敌人。 而且有一点是肯定的,就是:
我朋友的朋友是我的朋友。
我敌人的敌人也是我的朋友。
效果:任意顺序的合并操作以后,包 含k个节点的树的最大高度不超过lgk
ACM 竞赛培训
河南赛区赛题3
【 样例 】
河南赛区赛题4-枚举
在灾区,多数人已经受伤,缺水,少食物,精神处在崩溃的边缘。很多人的生存条件仅能维持几天。灾民 需要帐篷、衣物、食品和医疗器材、药品等物资。14日上午,中央军委委员、空军司令员许其亮组织召开 空军首长办公会,将空军下一步救灾重点确定为抢救伤员、空投、空运。空军各部队都派出多架运输机, 准备向灾区空运急需物品。 现在已知四种打包过的急需物品重量分别为C1, C2, C3,C4 ,数量分别为M1,M2,M3,M4包。一架运输 机的载重量为W, 现在各部队关心将一架运输机装满共有多少种运载方案,以便调度进行空运。 比如C={ 100, 200, 500, 1000},M={ 3, 2, 3, 1 }, W=1000, 一共有4种运载方案: 1000=100+100+100+200+500 1000=100+200+200+500 1000=500+500 1000=1000 【标准输入】 C1 C2 C3 C4 N 其中 N为空运的部队数 Mi1 Mi2 Mi3 Mi4 Wi 表示各运载部队需空运的4种物品数量Mi 和各自运输机的载重量Wi i=1,2,….. , N
河南赛区赛题2
【样 例】
河南赛区赛题3-排序查找算法
【试题三】 密码破译 某组织欲破获一个外星人的密码,密码由一定长度的字串组成。此组织拥有一些破译此密码 的长度不同的钥匙,若两个钥匙的长度之和恰好为此密码的长度,则此密码被成功破译。现 在就请你编程找出能破译此密码的两个钥匙。 【标准输入】 第一行: N N为钥匙的个数(1<=N<=1000) 第二行: L L为密码的长度 以下有N行: Ai 每一行是一把钥匙的长度 i=1,2,……,N 【标准输出】 若无法找到破译此密码的钥匙,则输出0 若找到两把破译的钥匙,则输出文件有两行,分别为两把钥匙的编号,按从小到大输出。若 有多种破译方案,则只输出包含起始编号最小的一组即可。 [【约束条件】 (1)1<= N,L,Ai <=1000(i=1, 2, ….., N ) (2)时间限制: 1000MS
ACM技术培训文档
VLAN设置 设置
•
802.1Q设置是在VLAN TRUNK环境下使用,如该设备接入到VLAN TRUNK环 境中,那么设备就要让trunk包从设备中通过,此时就要根据两端的VLAN ID分 别设置虚拟子接口,然后在子接口之间设置透明或者路由。 对于非VLAN TRUNK环境,在此不必做任何设置。
认证
• •
如果要用使用认证功能,这里首先要启用认证功能。 认证功能启用后,下一步要将认证网段指定出来,这里很关键,否则无法进 行认证。
认证网段及免认证
•
如果启用认证功能,则这里必须指定需要认证的网段,不在该网段内的用户 无法访问网络。 免认证IP必须在认证网段内,否则不生效。如果加入了免认证,则该用户上 网无限制。 免认证服务器是指启用认证后,对外提供服务的服务器ip不在认证范围内,任 何用户访问该服务器都无需认证。
备份与恢复
• •
•
备份与恢复分为两部分,一部分是备份,一部分是恢复。 这里的备份只能备份网络控制的配置文件,至于审计内容的备份在网络审计的 配置中去实现。同时,配置文件可事先下载保存,同时也支持将配置文件导入 上传的功能。 恢复出厂设置时在这里点击。
数据库表备份
• •
数据库表备份是指网络控制功能的数据库表备份。 备份出来的数据可在“上传/下载”表单里。
报警日志
•
报警日志是在模块规则中设置了阻断、告警等功能,如果有用户行为违反了 这些行为,系统会发出告警,这些告警会记录在这里。因此,阻断和告警是 否生效,可查看这里的报警日志,如果没有,说明该行为没有触发,换句话 是没有生效。
网络接入
• •
在“网络接入”中选择部署模式,以及配置网卡地址和接口类型。 注意:通常只选择内网作为监控模式,其他选择为“管理”即可。接口类型 中有“其他”,是指该接口外联数据库,设备将审计数据发送到外部数据库 。“管理”是指旁路接入时使用该接口进行设备管理。
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程序设计竞赛 培训 线段树共68页文档
45、法律的制定是为了保证每一个人 自由发 挥自己 的才能 ,而不 是为了 束缚他 的才能 。—— 罗伯斯 庇尔
6、最大的骄傲于最大的自卑都表示心灵的最软弱无力。——斯宾诺莎 7、自知之明是最难得的知识。——西班牙 8、勇气通往天堂,怯懦通往地狱。——塞内加 9、有时候读书是一种巧妙地避开思考的方法。——赫尔普斯 10、阅读一切好书同和过去最杰出的人谈话。——笛卡儿
浙江大学 acm程序设计竞赛 培训 线段树
41、实际上,我们想要的不是针对犯 罪的法 律,而 是针对 疯狂的 法律。 ——马 克·吐温 42、法律的力量应当跟随着公民,就 像影子 跟随着 身体一 样。— —贝卡 利亚 43、法律和制度必须跟上人类思想进 步。— —杰弗 逊 44、人类受制于法律,法律受制于情 理。— —托·富 勒
ACM培训精品PPT课件
DP (Dynamic Programming) 动态编程,动 态规划
DFS (Depth First Search) 深度优先搜索
BFS (Breadth First Search) 宽度/广度优先搜 索
输入输出
%d %lld %lf自动扫描前导空格 比如:读入5个整数到A[5]
输入文件中,数的排布是这个样子
35 26 78
99
206
不管它,直接5次%d
for ( int i = 0; i < 5; i++ ) scanf(“%d”, A + i);
%lld用于输入和输出长整数(long long,64位) %lf用于输入输出double
cout<<"j="; printf("%d\n", j); } return 0; }
0
1
j=0 j=1 j=2 j=3
2 3 4 j=j=j=j=j=
j=4
输入输出
scanf
输入格式
%d %lld %c %s %lf
对每种格式搞清楚一个重要问题
是否自动跳过前导空白?
什么是空白:空格,TAB,回车
输入输出
%s 读一个字符串,自动扫描前导空白,读到 空白结束
如: abcd efgh,将读出”abcd”
%c读一个字符,但是不扫描前导空白
如何读一个非空白字符呢?
比如,读取某人的信息,其性别用M/F表示
TopBoy M ComputerScience
Kitty
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题解分类
1475 Ranklist 没有完美解决,不知道您有没有好方法……
1572 Bracelet 题义不明,感觉可能是判定欧拉回路的存在性,但是过不去
动态规划:
1011 NTA 简单题
1013 Great Equipment 简单题
1024 Calendar Game 简单题
1027 Human Gene Functions 简单题
1239 Hanoi Tower Troubles Again! SRbGa的经典题……
字符串处理:
1050 Start Up the Startup 简单题
1315 Excuses, Excuses! 简单题
1350 The Drunk Jailer 简单题
1352 Number Base Conversion 简单题
1353 Unimodal Palindromic Decompositions 规模不大,所以是简单题……
1037 Gridland 简单题
1052 Algernon s Noxious Emissions 简单题
1409 Communication System 简单题,但是很容易看错~~~
1425 Crossed Matchings 简单题
1078 Palindrom Numbers 简单题
1086 Octal Fractions 简单题
1199 Point of Intersection 简单题
1104 Leaps Tall Buildings 简单题
1110 Dick and Jane 简单题
浙师大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程序设计竞赛动态规划讲义
最
优
三
角
如果没有红色虚线的部分,或许你会
形
认为决策应该是枚举子多边形内的
划 分
两点连线,然后分成两个子多边形. 这显然是不行的,因为计算机已经无 法再表示分割出来的子多边形了(不
能用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
ACM培训精品PPT课件
自己过滤空格?麻烦!
输入输出
读一个非空白字符, 方法一:
char str[2]; scanf(“%1s”, str); // %1s扫描前导空白,并且只读一个字符 char c = str[0]; 方法二: 强制扫描空白 在%前面加上一个空格表示“强制扫描前导空白” scanf(“ %c”, &ch); 前面那个读人物信息的完整scanf语句:
LCS (Longest Common Subsequence) 最长 公共子串
输入输出
C:
scanf printf
C++:
cin cout
速度快 格式容易控制
使用简单, 自动识别类型 格式控制较麻烦
数据规模较大时, 推荐(必须)使用scanf 以 避免超时(TLE)
输入输出
cout: 带缓冲输出 printf: 不带缓冲输出
Ctrl+Z 2.最好不要把C和C++的输入输出语句混着用,会造成一些莫名其妙的问题 3.我个人倾向于使用纯C的输入输出,因为方便且速度快。
关于重定向操作
当程序要输入的内容很多时,从文件读入的操作变得非常重 要,特别是需要调试时,这样可以避免你反复的从键盘敲入重
复的内容。
使用标准输入语句,可以使用重定向命令行
scanf(“%s %c %s”, name, &gender, ability);
输入输出
同理,我们也可以用其它字符来扫描其它类型 的无关输入
比如,输入年月日的信息
2007-08-03 scanf(“%d-%d-%d”, &y, &m, &d); 其它类似
浮点数的输入问题
为什么说while(in!=0.00)不合理呢? 如果不合理应该怎么判断!!