├── .gitignore ├── Makefile ├── README.md ├── fz.bat ├── fz.tex ├── resource └── tux.pdf ├── settings.tex ├── title.tex ├── tux.tex └── 模板 ├── 10_博弈.tex ├── 10_博弈 ├── 1_巴什博弈.cpp ├── 1_巴什博弈.tex ├── 2_尼姆博弈.cpp ├── 2_尼姆博弈.tex ├── 3_威佐夫博弈.cpp └── 3_威佐夫博弈.tex ├── 11_计算几何.tex ├── 11_计算几何 ├── 1_基本模板.cpp ├── 2_基本测试.cpp ├── 3_最近点对.tex ├── 3_最近点对 │ ├── cp_merge.cpp │ ├── cp_partition.cpp │ └── cp_sort.cpp ├── 4_Delaunay三角剖分.cpp ├── 5_几何对偶性.tex └── 5_几何对偶性 │ └── ex1.cpp ├── 12_其他.tex ├── 12_其他 ├── 1_编译器相关.tex ├── 1_编译器相关 │ ├── 1_强制O2优化.cpp │ ├── 2_G++(MinGW32)扩栈.cpp │ ├── 3_G++(64位linux)扩栈.cpp │ └── 4_C++扩栈.cpp ├── 2_输入输出优化.cpp ├── 3_位反转.cpp ├── 4_蔡勒公式.cpp ├── 4_蔡勒公式.tex ├── 5_坐标旋转变换.cpp ├── 5_坐标旋转变换.tex ├── 6_归并排序求逆序数.cpp ├── 7_奇怪的东西.tex ├── 7_奇怪的东西 │ ├── 1_格式化html标签.cpp │ └── 2_输出数字的英文表示.cpp └── 8_方向数组.cpp ├── 13_一些题目.tex ├── 13_一些题目 ├── 1.tex ├── 1_1.cpp ├── 1_2.cpp ├── 2.cpp ├── 2.tex ├── 3.cpp ├── 3.jpg ├── 3.tex ├── 4.cpp ├── 5.cpp └── 5.jpg ├── 1_设置.tex ├── 1_设置 ├── 1_头文件.cpp └── 2_Ubuntu相关设置.tex ├── 2_STL.tex ├── 2_STL ├── 1_STL.cpp └── bitset.tex ├── 3_基本算法.tex ├── 3_基本算法 ├── 1_二分.cpp └── 2_三分.cpp ├── 4_数据结构.tex ├── 4_数据结构 ├── 10_splay.cpp ├── 11_KD-tree.tex ├── 11_KD-tree │ ├── HDU2966.cpp │ └── HDU4347.cpp ├── 12_树链剖分.tex ├── 12_树链剖分 │ ├── HDU3966.cpp │ ├── POJ2763.cpp │ └── POJ3237.cpp ├── 1_离散化.cpp ├── 2_并查集.cpp ├── 3_树状数组.tex ├── 3_树状数组 │ ├── 1_一维树状数组.cpp │ ├── 2_一维树状数组区间更新区间查询.cpp │ └── 3_多维树状数组的处理.cpp ├── 4_RMQ.tex ├── 4_RMQ │ ├── 1_一维RMQ.cpp │ └── 2_二维RMQ.cpp ├── 5_线段树.tex ├── 5_线段树 │ ├── 1_单点更新.cpp │ ├── 2_区间更新.cpp │ ├── 3_对一棵树进行线段树操作.cpp │ ├── 4_二维线段树区间更新单点求和.cpp │ ├── 5_二维线段树单点更新区间求最大最小值.cpp │ ├── 6_线段树相关例题.tex │ ├── 6_线段树相关例题 │ │ ├── 区间更新 │ │ │ ├── 1_HDU1698.cpp │ │ │ ├── 2_POJ3468.cpp │ │ │ ├── 3_POJ2528.cpp │ │ │ ├── 4_POJ1436.cpp │ │ │ ├── 5_POJ2991.cpp │ │ │ ├── HDU4973.cpp │ │ │ └── ZOJProblemSet-3632.cpp │ │ └── 单点更新 │ │ │ ├── 1_HDU1166.cpp │ │ │ ├── 2_HDU1754.cpp │ │ │ ├── 3_HDU1394.cpp │ │ │ ├── 4_HDU2795.cpp │ │ │ ├── 5_POJ2828.cpp │ │ │ ├── 6_POJ2886.cpp │ │ │ ├── 7_HDU4288.cpp │ │ │ ├── 8_CF19D.cpp │ │ │ ├── 9_POJ2481.cpp │ │ │ └── ZOJProblemSet-3612.cpp │ └── 7_动态新建结点的线段树.cpp ├── 6_左偏树.cpp ├── 6_左偏树.tex ├── 7_划分树.cpp ├── 7_划分树.tex ├── 8_SBT.cpp ├── 9_可持久化线段树.tex └── 9_可持久化线段树 │ ├── 1_可持久化线段树.cpp │ ├── 2_树状数组套可持久化线段树.cpp │ ├── 3_POJ2104.cpp │ ├── 4_HDU4866.cpp │ └── 4_HDU4866.jpg ├── 5_字符串.tex ├── 5_字符串 ├── 1_KMP.cpp ├── 1_扩展KMP.cpp ├── 2_trie字典树.cpp ├── 3_AC自动机.cpp ├── 4_哈希.tex ├── 4_哈希 │ ├── 1_字符串哈希.cpp │ ├── 2_字符串矩阵哈希.cpp │ └── 3_哈希函数.cpp └── 5_字符串的最小表示法.cpp ├── 6_动态规划.tex ├── 6_动态规划 ├── 1_最大子段和.cpp ├── 2_二维最大子段和.cpp ├── 3_最长上升子序列(LIS).cpp ├── 4_最长公共子序列(LCS).cpp ├── 5_最长公共上升子序列(LCIS).cpp └── 6_数位DP.cpp ├── 7_数论.tex ├── 7_数论 ├── 0_判断质数.cpp ├── 10_欧拉函数打表.cpp ├── 11_中国剩余定理不互质.cpp ├── 12_组合数打表.cpp ├── 13_组合数在线.cpp ├── 14_lucas定理.cpp ├── 15_指数循环节.cpp ├── 15_指数循环节.tex ├── 16_Miller_Rabbin大素数测试.cpp ├── 1_筛法打质数表.cpp ├── 2_区间筛质数.cpp ├── 3_分解质因数.cpp ├── 4_因数个数打表.cpp ├── 5_快速乘法.cpp ├── 5_快速幂.cpp ├── 6_费马小定理求逆元.cpp ├── 6_费马小定理求逆元.tex ├── 7_扩展欧几里得.cpp ├── 8_扩展欧几里得求逆元.cpp ├── 8_扩展欧几里得求逆元.tex └── 9_欧拉函数.cpp ├── 8_图论.tex ├── 8_图论 ├── 10_树的直径.cpp ├── 11_二分图最大匹配匈牙利算法.cpp ├── 11_二分图最大匹配匈牙利算法.tex ├── 12_网络流Dinic算法.cpp ├── 13_LCA的tarjan离线算法.cpp ├── 14_2-SAT.cpp ├── 14_2-SAT_usage.cpp ├── 15_拓扑排序.tex ├── 15_拓扑排序 │ ├── 1_Kahn.cpp │ └── 2_DFS.cpp ├── 1_邻接表.cpp ├── 2_spfa.cpp ├── 3_dijkstra.cpp ├── 4_dijkstra+heap.cpp ├── 5_floyd_warshall.cpp ├── 6_kruskal.cpp ├── 7_prim.cpp ├── 8_prim+heap.cpp └── 9_最小树形图朱刘算法.cpp ├── 9_数学.tex ├── 9_数学 ├── 10_格雷码.cpp ├── 11_表达式求值.cpp ├── 12_卡特兰数.tex ├── 13_求和公式.tex ├── 14_小公式.tex ├── 15_快速傅里叶变换.cpp ├── 15_快速傅里叶变换.tex ├── 1_高斯消元.cpp ├── 2_二进制下的高斯消元.cpp ├── 3_高精度整数类.tex ├── 3_高精度整数类 │ ├── 1_stack.cpp │ ├── 2_heap.cpp │ ├── 3_FFTmul.cpp │ └── 4_FNTTmul.cpp ├── 4_分数类.cpp ├── 4_分数类.tex ├── 5_矩阵类.cpp ├── 6_分治法等比数列求和.cpp ├── 6_分治法等比数列求和.tex ├── 7_自适应Simpson积分法.cpp ├── 8_Romberg积分法.cpp ├── 9_De_Bruijn序列.cpp └── 9_De_Bruijn序列.tex └── 现场赛宝典.tex /.gitignore: -------------------------------------------------------------------------------- 1 | fz.aux 2 | fz.log 3 | fz.out 4 | fz.toc 5 | fz.pdf 6 | *.orig 7 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | all: pdf 2 | 3 | pdf: fz.tex 4 | astyle *.cpp -r -A1 --indent=spaces=4 5 | xelatex fz.tex 6 | xelatex fz.tex 7 | 8 | clean: 9 | rm -f fz.aux fz.log fz.out fz.toc fz.pdf 10 | rm -f `find . -name *.orig` 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ACM/ICPC Template by fz 2 | 3 | 这是我在本科期间参加ACM/ICPC时整理的一些算法模板,在此之后依然进行了少量更新。 4 | 5 | 本模板采用LaTeX编写。 6 | 7 | # Building 8 | 9 | 建议安装Tex Live进行编译: 10 | 11 | * Windows: 下载安装[Tex Live](https://mirrors.tuna.tsinghua.edu.cn/CTAN/systems/texlive/Images/)。 12 | * Linux: 直接在软件源中安装。例如Debian系的用户可以`sudo apt install texlive-full`。 13 | 14 | 执行`make`即可编译,Windows用户可以执行`fz.bat`。 15 | 16 | # Advice 17 | 18 | * 如果只需要编译后的文档,建议直接下载[Release](https://github.com/fz568573448/ACM-ICPC-Template/releases)。 19 | * 如需打印,建议双面打印,因为针对双面打印做了一些优化。 20 | * 编译时,Linux下需要添加部分字体。 21 | * 编译时,较新版本的Tex Live的listings包对引号的行为有些不同,可以参考[这篇文章](https://debug.fanzheng.org/post/latex-package-listings-quote.html)。 22 | -------------------------------------------------------------------------------- /fz.bat: -------------------------------------------------------------------------------- 1 | xelatex fz.tex 2 | xelatex fz.tex 3 | -------------------------------------------------------------------------------- /fz.tex: -------------------------------------------------------------------------------- 1 | \documentclass[a4paper, 12pt, twoside]{article} 2 | 3 | \setlength{\columnsep}{0.8cm} 4 | \usepackage{xeCJK} 5 | \setsansfont{Consolas} 6 | \setmonofont{Consolas} 7 | %\setmainfont{Consolas} 8 | 9 | \setCJKmainfont{SimHei} 10 | \setCJKsansfont{SimHei} 11 | \setCJKmonofont{SimHei} 12 | 13 | % \usepackage{textcomp} 14 | \usepackage{xcolor} 15 | \usepackage{listings} 16 | \lstset{ 17 | language=C++, 18 | breaklines=true, 19 | tabsize=4, 20 | basicstyle=\sf\footnotesize, 21 | numberstyle=\sf\footnotesize, 22 | commentstyle=\sf\footnotesize, 23 | numbers=left, 24 | frame=leftline, 25 | escapeinside=``, 26 | extendedchars=false, 27 | showstringspaces=false, 28 | keywordstyle={\bfseries\color{blue}}, 29 | commentstyle=\color[RGB]{40, 147, 40}, 30 | stringstyle=\color[RGB]{163, 21, 21}, 31 | upquote=true 32 | } 33 | 34 | \usepackage{geometry} 35 | \geometry{left=2cm,right=2cm,top=1.2cm,bottom=1.8cm,headsep=0.1cm,footnotesep=0.5cm} 36 | \usepackage{courier} 37 | 38 | \usepackage[ 39 | CJKbookmarks=true, 40 | colorlinks, 41 | linkcolor=black, 42 | anchorcolor=black, 43 | citecolor=black 44 | ]{hyperref} 45 | \AtBeginDvi{\special{pdf:tounicode UTF8-UCS2}} 46 | 47 | \usepackage{fancyhdr} 48 | 49 | \usepackage{sectsty} 50 | \sectionfont{\large} 51 | \subsectionfont{\large} 52 | \subsubsectionfont{\large} 53 | 54 | \usepackage{amsmath} 55 | \usepackage{booktabs} 56 | 57 | \usepackage{indentfirst} 58 | \setlength{\parindent}{0em} 59 | 60 | \usepackage{graphicx} 61 | 62 | \begin{document} 63 | \input settings.tex 64 | \input title.tex 65 | 66 | \clearpage 67 | 此页为双面打印之留白页\\ 68 | 打印需注意:选择双面打印,并缩放到可打印区域! 69 | \clearpage 70 | 71 | \setcounter{page}{1} 72 | \pagenumbering{Roman} 73 | \tableofcontents\cleardoublepage 74 | \setcounter{page}{1} 75 | \pagenumbering{arabic} 76 | 77 | \input ./模板/1_设置.tex 78 | \input ./模板/2_STL.tex 79 | \input ./模板/3_基本算法.tex 80 | \input ./模板/4_数据结构.tex 81 | \input ./模板/5_字符串.tex 82 | \input ./模板/6_动态规划.tex 83 | \input ./模板/7_数论.tex 84 | \input ./模板/8_图论.tex 85 | \input ./模板/9_数学.tex 86 | \input ./模板/10_博弈.tex 87 | \input ./模板/11_计算几何.tex 88 | \input ./模板/12_其他.tex 89 | \input ./模板/13_一些题目.tex 90 | \clearpage 91 | \input ./模板/现场赛宝典.tex 92 | \end{document} 93 | -------------------------------------------------------------------------------- /resource/tux.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zheng-fan/ACM-ICPC-Template/d66826512103ef35e1436b68f7ee2201cb3bff09/resource/tux.pdf -------------------------------------------------------------------------------- /settings.tex: -------------------------------------------------------------------------------- 1 | \pagestyle{fancy} 2 | %\lhead{} 3 | %\chead{} 4 | %\rhead{\bfseries ACM/ICPC Template by fz} 5 | %\lfoot{} 6 | %\cfoot{} 7 | %\rfoot{\bfseries\thepage} 8 | \fancyfoot[C]{} 9 | \fancyfoot[LE,RO]{\bfseries\thepage} 10 | \fancyhead[C]{\bfseries ACM/ICPC Template by fz} 11 | -------------------------------------------------------------------------------- /title.tex: -------------------------------------------------------------------------------- 1 | \newgeometry{left=1cm,right=1cm,top=1.5cm,bottom=1.5cm} 2 | \begin{titlepage} 3 | \pagestyle{empty} 4 | 5 | \begin{center} 6 | ~\\[80pt] 7 | \fontsize{40pt}{\baselineskip}\selectfont \textsc{\textbf{ACM/ICPC TEMPLATE}}\\[32pt] 8 | \rule{\textwidth}{2pt}\ \\[8pt] 9 | ~\\[20pt] 10 | \begin{figure}[!h] 11 | \centering 12 | \def\svgwidth{320pt} 13 | \input{tux.tex} 14 | \end{figure} 15 | 16 | ~\\[20pt] 17 | \Huge\textbf{fz}\\[14pt] 18 | \Large\textbf{Last build at \today} 19 | \end{center} 20 | \end{titlepage} 21 | \restoregeometry 22 | 23 | %\begin{newpage} 24 | %\pagestyle{empty} 25 | %$ $\clearpage 26 | %\end{newpage} 27 | %\cleardoublepage 28 | -------------------------------------------------------------------------------- /tux.tex: -------------------------------------------------------------------------------- 1 | %% Creator: Inkscape inkscape 0.48.4, www.inkscape.org 2 | %% PDF/EPS/PS + LaTeX output extension by Johan Engelen, 2010 3 | %% Accompanies image file 'tux.pdf' (pdf, eps, ps) 4 | %% 5 | %% To include the image in your LaTeX document, write 6 | %% \input{.pdf_tex} 7 | %% instead of 8 | %% \includegraphics{.pdf} 9 | %% To scale the image, write 10 | %% \def\svgwidth{} 11 | %% \input{.pdf_tex} 12 | %% instead of 13 | %% \includegraphics[width=]{.pdf} 14 | %% 15 | %% Images with a different path to the parent latex file can 16 | %% be accessed with the `import' package (which may need to be 17 | %% installed) using 18 | %% \usepackage{import} 19 | %% in the preamble, and then including the image with 20 | %% \import{}{.pdf_tex} 21 | %% Alternatively, one can specify 22 | %% \graphicspath{{/}} 23 | %% 24 | %% For more information, please see info/svg-inkscape on CTAN: 25 | %% http://tug.ctan.org/tex-archive/info/svg-inkscape 26 | %% 27 | \begingroup% 28 | \makeatletter% 29 | \providecommand\color[2][]{% 30 | \errmessage{(Inkscape) Color is used for the text in Inkscape, but the package 'color.sty' is not loaded}% 31 | \renewcommand\color[2][]{}% 32 | }% 33 | \providecommand\transparent[1]{% 34 | \errmessage{(Inkscape) Transparency is used (non-zero) for the text in Inkscape, but the package 'transparent.sty' is not loaded}% 35 | \renewcommand\transparent[1]{}% 36 | }% 37 | \providecommand\rotatebox[2]{#2}% 38 | \ifx\svgwidth\undefined% 39 | \setlength{\unitlength}{462.50026324bp}% 40 | \ifx\svgscale\undefined% 41 | \relax% 42 | \else% 43 | \setlength{\unitlength}{\unitlength * \real{\svgscale}}% 44 | \fi% 45 | \else% 46 | \setlength{\unitlength}{\svgwidth}% 47 | \fi% 48 | \global\let\svgwidth\undefined% 49 | \global\let\svgscale\undefined% 50 | \makeatother% 51 | \begin{picture}(1,1.19076017)% 52 | \put(0,0){\includegraphics[width=\unitlength]{resource/tux.pdf}}% 53 | \end{picture}% 54 | \endgroup% 55 | -------------------------------------------------------------------------------- /模板/10_博弈.tex: -------------------------------------------------------------------------------- 1 | \section{博弈} 2 | \subsection{巴什博弈} 3 | \input ./模板/10_博弈/1_巴什博弈.tex 4 | \lstinputlisting{"./模板/10_博弈/1_巴什博弈.cpp"} 5 | 6 | \subsection{尼姆博弈} 7 | \input ./模板/10_博弈/2_尼姆博弈.tex 8 | \lstinputlisting{"./模板/10_博弈/2_尼姆博弈.cpp"} 9 | 10 | \subsection{威佐夫博弈} 11 | \input ./模板/10_博弈/3_威佐夫博弈.tex 12 | \lstinputlisting{"./模板/10_博弈/3_威佐夫博弈.cpp"} 13 | -------------------------------------------------------------------------------- /模板/10_博弈/1_巴什博弈.cpp: -------------------------------------------------------------------------------- 1 | int bash(int n, int m) 2 | { 3 | if(n%(m+1) != 0) return 1; 4 | else return 0; 5 | } 6 | int main() 7 | { 8 | int n,m; 9 | while(~scanf("%d%d",&n,&m)) 10 | { 11 | if (bash(n,m)) 12 | { 13 | if (n>m) 14 | printf("%d",n%(m+1)); 15 | else 16 | { 17 | printf("%d",n); 18 | for (int i=n+1; i<=m; i++) 19 | printf(" %d",i); 20 | } 21 | puts(""); 22 | } 23 | else puts("none"); 24 | } 25 | return 0; 26 | } 27 | -------------------------------------------------------------------------------- /模板/10_博弈/1_巴什博弈.tex: -------------------------------------------------------------------------------- 1 | 只有一堆$n$个物品,两个人轮流从这堆物品中取物,规定每次至少取一个,最多取$m$个。最后取光者得胜。 -------------------------------------------------------------------------------- /模板/10_博弈/2_尼姆博弈.cpp: -------------------------------------------------------------------------------- 1 | int sg(int n,int numsg[]) 2 | { 3 | int ans = 0; 4 | for(int i=1; i <= n; i++) 5 | ans ^= numsg[i]; 6 | if(ans == 0) 7 | printf("No\n"); 8 | else 9 | { 10 | printf("Yes\n"); 11 | for(int i = 1; i <= n; i++) 12 | { 13 | int x = ans ^ numsg[i]; 14 | if(x < numsg[i]) 15 | printf("%d %d\n", numsg[i], x); 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /模板/10_博弈/2_尼姆博弈.tex: -------------------------------------------------------------------------------- 1 | 有$m$堆各若干个物品,两个人轮流从某一堆取任意多的物品,规定每次至少取一个,多者不限,最后取光者得胜。 -------------------------------------------------------------------------------- /模板/10_博弈/3_威佐夫博弈.cpp: -------------------------------------------------------------------------------- 1 | int wzf(int n, int m) 2 | { 3 | if(n > m) 4 | swap(n, m); 5 | int k = m-n; 6 | int a = (k * (1.0 + sqrt(5.0))/2.0); 7 | if(a == n) 8 | return 0; 9 | else 10 | return 1; 11 | } 12 | int main() 13 | { 14 | int a,b; 15 | while(scanf("%d%d",&a,&b),a|b) 16 | { 17 | if (wzf(a,b)) 18 | { 19 | puts("1"); 20 | if(a>b) 21 | swap(a,b); 22 | //第一种 23 | int k=b-a; 24 | double q=(1+sqrt(5.0))/2; 25 | int ak=k*q; 26 | //特殊情况 27 | if(a==0) 28 | puts("0 0"); 29 | //同时减 30 | if(a>=ak) 31 | printf("%d %d\n",ak,ak+k); 32 | for (int i=1; i<=b; i++) 33 | { 34 | //b减一点 35 | if(a==(int)(i*q)&&b>a+i) 36 | printf("%d %d\n",a,a+i); 37 | //b减很多 38 | if(a==(int)(i*q)+i) 39 | printf("%d %d\n",a-i,a); 40 | //a减一点 41 | if(b==(int)(i*q)+i&&b-i=0,j>=0; i--,j--) 47 | if(wzf(i,j)==0) 48 | { 49 | cout<=0; i--) 54 | if(wzf(i,b)==0) 55 | { 56 | cout<=0; i--) 60 | if(wzf(i,a)==0) 61 | { 62 | //b减很多 63 | if (i0) return 1; 15 | if (res==0) return 0; 16 | return -1; 17 | } 18 | //in-Circle-Test 19 | double det3(double a11,double a12,double a13,double a21,double a22,double a23,double a31,double a32,double a33) 20 | { 21 | return a11*(a22*a33-a32*a23)-a12*(a21*a33-a31*a23)+a13*(a21*a32-a31*a22); 22 | } 23 | int inCircle(const point &a,const point &b,const point &c,const point &p) 24 | { 25 | double as=a.x*a.x+a.y*a.y; 26 | double bs=b.x*b.x+b.y*b.y; 27 | double cs=c.x*c.x+c.y*c.y; 28 | double ps=p.x*p.x+p.y*p.y; 29 | double ans=a.x*det3(b.y,bs,1,c.y,cs,1,p.y,ps,1) 30 | -a.y*det3(b.x,bs,1,c.x,cs,1,p.x,ps,1) 31 | +as*det3(b.x,b.y,1,c.x,c.y,1,p.x,p.y,1) 32 | -det3(b.x,b.y,bs,c.x,c.y,cs,p.x,p.y,ps); 33 | if (ans>0) return 1; 34 | if (ans==0) return 0; 35 | return -1; 36 | } 37 | //in-Triangle-Test 38 | int inTriangle(const point &a,const point &b,const point &c,const point &p) 39 | { 40 | int l1=to_left(a,b,p); 41 | int l2=to_left(b,c,p); 42 | int l3=to_left(c,a,p); 43 | if (l1==0||l2==0||l3==0) return 0; 44 | return l1==l2&&l2==l3?1:-1; 45 | } 46 | -------------------------------------------------------------------------------- /模板/11_计算几何/3_最近点对.tex: -------------------------------------------------------------------------------- 1 | \lstinputlisting{"./模板/11_计算几何/3_最近点对/cp_sort.cpp"} 2 | \lstinputlisting{"./模板/11_计算几何/3_最近点对/cp_partition.cpp"} 3 | \lstinputlisting{"./模板/11_计算几何/3_最近点对/cp_merge.cpp"} 4 | -------------------------------------------------------------------------------- /模板/11_计算几何/3_最近点对/cp_merge.cpp: -------------------------------------------------------------------------------- 1 | const int NV=300005; 2 | struct point 3 | { 4 | double x, y; 5 | void in() 6 | { 7 | scanf("%lf%lf",&x,&y); 8 | } 9 | } p[NV],py[NV]; 10 | int pyidx[NV]; 11 | bool cmpX(const point &p1,const point &p2) 12 | { 13 | return p1.x>1; 29 | double delta=min(ClosestPair(l,m),ClosestPair(m+1,r)); //\delta=\min(\delta_1,\delta_2) 30 | inplace_merge(py+l,py+m+1,py+r+1,cmpY); //利用归并排序的思想合并得到按y有序的序列 31 | int cnt=0; 32 | for (int i=l; i<=r; i++) //把所有x坐标在p[m].x的[-delta, delta]的点取出来 33 | { 34 | if(p[m].x-delta<=py[i].x&&py[i].x<=p[m].x+delta) 35 | pyidx[cnt++]=i; 36 | } 37 | for(int i=0; i=delta) break; //最多寻找6个点后一定会break 41 | delta=min(delta,dis(py[pyidx[i]],py[pyidx[j]])); 42 | } 43 | return delta; 44 | } 45 | void init(int n) 46 | { 47 | for (int i=0; i>n; 55 | init(n); //input and presort 56 | printf("%.2f\n",ClosestPair(0,n-1)); 57 | return 0; 58 | } 59 | -------------------------------------------------------------------------------- /模板/11_计算几何/3_最近点对/cp_partition.cpp: -------------------------------------------------------------------------------- 1 | const int NV=300005; 2 | struct point 3 | { 4 | double x, y; 5 | void in() 6 | { 7 | scanf("%lf%lf",&x,&y); 8 | } 9 | } p[NV],py[NV],pytmp[NV]; 10 | int pyidx[NV]; 11 | bool cmpX(const point &p1,const point &p2) 12 | { 13 | return p1.x>1; 33 | midline=p[m].x; 34 | vector pytmp(py+l,py+r+1); //在进行划分操作导致改变y的有序性之前先记录一下 35 | stable_partition(py+l,py+r+1,pred); //对按y排序的数组用中间线划分 36 | double delta=min(ClosestPair(l,m),ClosestPair(m+1,r)); //\delta=\min(\delta_1,\delta_2) 37 | int cnt=0; 38 | for (int i=0; i<=r-l; i++) //把所有x坐标在p[m].x的[-delta, delta]的点取出来 39 | { 40 | if(p[m].x-delta<=pytmp[i].x&&pytmp[i].x<=p[m].x+delta) 41 | pyidx[cnt++]=i; 42 | } 43 | for(int i=0; i=delta) break; //最多寻找6个点后一定会break 47 | delta=min(delta,dis(pytmp[pyidx[i]],pytmp[pyidx[j]])); 48 | } 49 | return delta; 50 | } 51 | void init(int n) 52 | { 53 | for (int i=0; i>n; 62 | init(n); //input and presort 63 | printf("%.2f\n",ClosestPair(0,n-1)); 64 | return 0; 65 | } 66 | -------------------------------------------------------------------------------- /模板/11_计算几何/3_最近点对/cp_sort.cpp: -------------------------------------------------------------------------------- 1 | const int NV=300005; 2 | struct point 3 | { 4 | double x, y; 5 | void in() 6 | { 7 | scanf("%lf%lf",&x,&y); 8 | } 9 | } p[NV]; 10 | int pyidx[NV]; 11 | bool cmpX(const point &p1,const point &p2) 12 | { 13 | return p1.x>1; 28 | double delta=min(ClosestPair(l,m),ClosestPair(m+1,r)); //\delta=\min(\delta_1,\delta_2) 29 | int cnt=0; 30 | for (int i=l; i<=r; i++) //把所有x坐标在p[m].x的[-delta, delta]的点取出来 31 | { 32 | if(p[m].x-delta<=p[i].x&&p[i].x<=p[m].x+delta) 33 | pyidx[cnt++]=i; 34 | } 35 | sort(pyidx,pyidx+cnt,cmpY); 36 | for(int i=0; i=delta) break; //最多寻找6个点后一定会break 40 | delta=min(delta,dis(p[pyidx[i]],p[pyidx[j]])); 41 | } 42 | return delta; 43 | } 44 | void init(int n) 45 | { 46 | for (int i=0; i>n; 53 | init(n); //input and presort 54 | printf("%.2f\n",ClosestPair(0,n-1)); 55 | return 0; 56 | } 57 | -------------------------------------------------------------------------------- /模板/11_计算几何/5_几何对偶性.tex: -------------------------------------------------------------------------------- 1 | 利用对偶性,我们可以将点问题与线问题互相转化。 \\ 2 | 我们说方程为$y=kx+b$的直线与坐标为$(k,b)$的点是对偶的。 \\ 3 | 4 | 例如典型的半平面交问题,我们可以做如下变换: \\ 5 | 按半平面的方向将所有的半平面分成两部分,分别是朝$y$的正方向和朝$y$的负方向。 \\ 6 | 我们对所有方向向上的半平面对偶出来的点取上凸包,对所有方向向下的半平面对偶出来的点取下凸包,则得到的两个半凸包包含了哪些点就意味着半平面交得到的两个半凸包包含了哪些直线。 \\ 7 | 这对于半平面交的存在性判定非常有帮助。 \\ 8 | 不过其中平行于y轴的直线会存在问题。我们可以做一些特殊处理:将$x=b$换成$y=\inf x-b\inf$的形式。若方向向左,则认为它是方向向上;若方向向右,则认为它是方向向下。但这样是不可能做到精确的。 \\ 9 | 10 | 我们看一个例题: 11 | 12 | 现在我们有$n$条垂直于水平线的竖直线段,问能否找到一条直线,使之可以穿过的线段。我们约定,如果某条直线恰好穿过了线段的端点也表示它穿过了这个线段。 \\ 13 | 14 | 可以证明,我们可以把每个线段上端点对偶成向下的半平面,下端点对偶成向上的半平面,转化该问题为半平面交问题,如果半平面交为空则不存在一条直线满足题意。(半平面交为一个点也算是不为空) \\ 15 | 接着我们再做一次对偶,把两个半平面交问题转化为两个半凸包问题,只要得到的两个半凸包的交为空,则存在这样的直线。(交成一个点也算是为空) \\ 16 | 17 | 但是这种做法只适用于所有的线段平行的情形下。如果是任意的线段,那该问题在对偶为半平面交的问题时,会存在double edge的情况,那么在对偶到凸包问题时是有问题的,不能简单地用$y$高度来决定它是属于上端点还是下端点。类似地我们要把半平面交的“或”的情况加上去,这种“或”的结果就是两个端点的归属是可以互换的。 \\ 18 | 19 | 所以在对于不平行的情况下,问题其实就是在每个线段中选一个端点组成一个集合,另外一个组成一个集合,求两个集合的半凸包,只要存在一个这样的集合方案使得凸包没有交,那么就答案就是存在。这就是一个可分割性的问题了。 \\ 20 | 21 | \lstinputlisting{"./模板/11_计算几何/5_几何对偶性/ex1.cpp"} 22 | -------------------------------------------------------------------------------- /模板/11_计算几何/5_几何对偶性/ex1.cpp: -------------------------------------------------------------------------------- 1 | template inline void RD(T &ret) 2 | { 3 | char c; 4 | int sgn; 5 | while(c!='-'&&(c<'0'||c>'9')) 6 | c=getchar(); 7 | sgn=(c=='-')?-1:1; 8 | ret=(c=='-')?0:(c-'0'); 9 | while(c=getchar(),c>='0'&&c<='9') 10 | ret=ret*10+(c-'0'); 11 | ret*=sgn; 12 | } 13 | struct point 14 | { 15 | long long x,y; 16 | point(const long long &x = 0, const long long &y = 0): x(x), y(y) {} 17 | friend bool operator < (const point &a, const point &b) 18 | { 19 | return a.x-b.x<0||a.x-b.x==0&&a.y-b.y<0; 20 | } 21 | }; 22 | int to_left(const point &a,const point &b,const point &t) 23 | { 24 | long long res=(b.x-a.x)*(t.y-a.y)-(b.y-a.y)*(t.x-a.x); 25 | if (res>0) return 1; 26 | if (res==0) return 0; 27 | return -1; 28 | } 29 | const int NV=100005; 30 | point u[NV],d[NV]; 31 | point ansu[NV],ansd[NV]; 32 | int cntu,cntd; 33 | int vi,ei; //for judge 34 | int getHalfConvexHullAndJudge(int n) 35 | { 36 | sort(u+1,u+1+n); 37 | cntu=0; 38 | for (int i=1; i<=n; i++) //lowerhull of upper points 39 | { 40 | while(cntu>1&&to_left(ansu[cntu-1],ansu[cntu],u[i])<=0) cntu--; 41 | ansu[++cntu]=u[i]; 42 | } 43 | sort(d+1,d+1+n); 44 | cntd=0; 45 | for (int i=1; i<=n; i++) //upperhull of lower points 46 | { 47 | while(cntd>1&&to_left(ansd[cntd-1],ansd[cntd],d[i])>=0) cntd--; 48 | ansd[++cntd]=d[i]; 49 | } 50 | //judge convex hull intersection 51 | vi=ei=1; 52 | while(vi<=n&&eiansu[ei+1].x) ei++; 56 | else 57 | { 58 | if (to_left(ansu[ei],ansu[ei+1],d[vi])==1) return 1; 59 | vi++; 60 | } 61 | } 62 | vi=ei=1; 63 | while(vi<=n&&eiansd[ei+1].x) ei++; 67 | else 68 | { 69 | if (to_left(ansd[ei],ansd[ei+1],u[vi])==-1) return 1; 70 | vi++; 71 | } 72 | } 73 | return 0; 74 | } 75 | int main() 76 | { 77 | setvbuf(stdin,new char[1<<20],_IOFBF,1<<20); 78 | setvbuf(stdout,new char[1<<20],_IOFBF,1<<20); 79 | int m; 80 | RD(m); 81 | while(m--) 82 | { 83 | int n; 84 | RD(n); 85 | for (int i=1; i<=n; i++) 86 | { 87 | int x,y1,y2; 88 | RD(x),RD(y1),RD(y2); 89 | if (y1>y2) swap(y1,y2); 90 | d[i]=point(x,y1); 91 | u[i]=point(x,y2); 92 | } 93 | if (getHalfConvexHullAndJudge(n)) putchar('N'); 94 | else putchar('Y'); 95 | } 96 | puts(""); 97 | return 0; 98 | } 99 | -------------------------------------------------------------------------------- /模板/12_其他.tex: -------------------------------------------------------------------------------- 1 | \section{其他} 2 | 3 | \input ./模板/12_其他/1_编译器相关.tex 4 | 5 | \subsection{输入输出优化} 6 | \lstinputlisting{"./模板/12_其他/2_输入输出优化.cpp"} 7 | 8 | \subsection{位反转} 9 | \lstinputlisting{"./模板/12_其他/3_位反转.cpp"} 10 | 11 | \subsection{蔡勒公式} 12 | \input ./模板/12_其他/4_蔡勒公式.tex 13 | \lstinputlisting{"./模板/12_其他/4_蔡勒公式.cpp"} 14 | 15 | \subsection{坐标旋转变换} 16 | \input ./模板/12_其他/5_坐标旋转变换.tex 17 | \lstinputlisting{"./模板/12_其他/5_坐标旋转变换.cpp"} 18 | 19 | \subsection{归并排序求逆序数} 20 | \lstinputlisting{"./模板/12_其他/6_归并排序求逆序数.cpp"} 21 | 22 | \subsection{奇怪的东西} 23 | \input ./模板/12_其他/7_奇怪的东西.tex 24 | -------------------------------------------------------------------------------- /模板/12_其他/1_编译器相关.tex: -------------------------------------------------------------------------------- 1 | \subsection{编译器相关} 2 | \subsubsection{强制O2优化} 3 | \lstinputlisting{"./模板/12_其他/1_编译器相关/1_强制O2优化.cpp"} 4 | 5 | \subsubsection{G++(MinGW32)扩栈} 6 | \lstinputlisting{"./模板/12_其他/1_编译器相关/2_G++(MinGW32)扩栈.cpp"} 7 | 8 | \subsubsection{G++(64位linux)扩栈} 9 | \lstinputlisting{"./模板/12_其他/1_编译器相关/3_G++(64位linux)扩栈.cpp"} 10 | 11 | \subsubsection{C++扩栈} 12 | \lstinputlisting{"./模板/12_其他/1_编译器相关/4_C++扩栈.cpp"} 13 | -------------------------------------------------------------------------------- /模板/12_其他/1_编译器相关/1_强制O2优化.cpp: -------------------------------------------------------------------------------- 1 | #pragma GCC optimize(2) 2 | -------------------------------------------------------------------------------- /模板/12_其他/1_编译器相关/2_G++(MinGW32)扩栈.cpp: -------------------------------------------------------------------------------- 1 | int SIZE_OF_STACK = 256 << 20; // 256MB 2 | char *p = (char*)malloc(SIZE_OF_STACK) + SIZE_OF_STACK; 3 | __asm__("movl %0, %%esp\n" :: "r"(p)); 4 | -------------------------------------------------------------------------------- /模板/12_其他/1_编译器相关/3_G++(64位linux)扩栈.cpp: -------------------------------------------------------------------------------- 1 | ///只在会爆栈的函数前后使用汇编语句会更安全 2 | ///但要注意避免使用局部变量保存函数返回值 3 | long rsp; 4 | int main() 5 | { 6 | int SIZE_OF_STACK = 256 << 20; // 256MB 7 | char *p = (char*)malloc(SIZE_OF_STACK) + SIZE_OF_STACK; 8 | __asm__("movq %%rsp, %0" :: "m"(rsp)); 9 | __asm__("movq %0, %%rsp" :: "r"(p)); 10 | 11 | //程序体 12 | 13 | __asm__("movq %0, %%rsp\n" :: "m"(rsp)); 14 | return 0; 15 | } 16 | -------------------------------------------------------------------------------- /模板/12_其他/1_编译器相关/4_C++扩栈.cpp: -------------------------------------------------------------------------------- 1 | #pragma comment(linker, "/STACK:102400000,102400000") 2 | -------------------------------------------------------------------------------- /模板/12_其他/2_输入输出优化.cpp: -------------------------------------------------------------------------------- 1 | template inline void RD(T &ret) 2 | { 3 | char c; 4 | do c=getchar(); 5 | while(c<'0'||c>'9'); 6 | ret=c-'0'; 7 | while((c=getchar())>='0'&&c<='9') 8 | ret=ret*10+(c-'0'); 9 | } 10 | template inline void OT(T a) 11 | { 12 | if(a>=10) OT(a/10); 13 | putchar(a%10+'0'); 14 | } 15 | ///有前导零的OT,主要在输出前要将输出数值加上lzexp 16 | const int lznum=4; 17 | const int lzexp=pow(10,lznum)+0.5; 18 | template inline void OT0(T a,int x=lznum-1) 19 | { 20 | if(a>=10||x) OT0(a/10,x-1); 21 | putchar(a%10+'0'); 22 | } 23 | ///支持负数的RD 24 | template inline void RD(T &ret) 25 | { 26 | char c=getchar(); 27 | int sgn; 28 | while(c!='-'&&(c<'0'||c>'9')) c=getchar(); 29 | sgn=(c=='-')?-1:1; 30 | ret=(c=='-')?0:(c-'0'); 31 | while(c=getchar(),c>='0'&&c<='9') ret=ret*10+(c-'0'); 32 | ret*=sgn; 33 | } 34 | ///吃掉空格与换行的getchar 35 | inline char fzgetchar() 36 | { 37 | char c; 38 | while(1) 39 | { 40 | c=getchar(); 41 | if (c!=' '&&c!='\n') break; 42 | } 43 | return c; 44 | } 45 | ///设置设置I/O缓存 46 | setvbuf(stdin,new char[1<<20],_IOFBF,1<<20); 47 | setvbuf(stdout,new char[1<<20],_IOFBF,1<<20); 48 | -------------------------------------------------------------------------------- /模板/12_其他/3_位反转.cpp: -------------------------------------------------------------------------------- 1 | inline int reversebits(int x) 2 | { 3 | x = ((x >> 1) & 0x55555555) | ((x << 1) & 0xaaaaaaaa); 4 | x = ((x >> 2) & 0x33333333) | ((x << 2) & 0xcccccccc); 5 | x = ((x >> 4) & 0x0f0f0f0f) | ((x << 4) & 0xf0f0f0f0); 6 | x = ((x >> 8) & 0x00ff00ff) | ((x << 8) & 0xff00ff00); 7 | x = ((x >>16) & 0x0000ffff) | ((x <<16) & 0xffff0000); 8 | return x; 9 | } 10 | 11 | inline long long reversebits(long long x) 12 | { 13 | x = ((x >> 1) & 0x5555555555555555LL) | ((x << 1) & 0xaaaaaaaaaaaaaaaaLL); 14 | x = ((x >> 2) & 0x3333333333333333LL) | ((x << 2) & 0xccccccccccccccccLL); 15 | x = ((x >> 4) & 0x0f0f0f0f0f0f0f0fLL) | ((x << 4) & 0xf0f0f0f0f0f0f0f0LL); 16 | x = ((x >> 8) & 0x00ff00ff00ff00ffLL) | ((x << 8) & 0xff00ff00ff00ff00LL); 17 | x = ((x >>16) & 0x0000ffff0000ffffLL) | ((x <<16) & 0xffff0000ffff0000LL); 18 | x = ((x >>32) & 0x00000000ffffffffLL) | ((x <<32) & 0xffffffff00000000LL); 19 | return x; 20 | } 21 | -------------------------------------------------------------------------------- /模板/12_其他/4_蔡勒公式.cpp: -------------------------------------------------------------------------------- 1 | int zeller(int y,int m,int d,int flag) 2 | { 3 | if (m==1||m==2) 4 | y--,m+=12; 5 | int c=y/100; 6 | y%=100; 7 | int w=((c/4-2*c+y+y/4+13*(m+1)/5+d-1)%7+7)%7; 8 | if (flag) return (w+3)%7; 9 | return w; 10 | } 11 | -------------------------------------------------------------------------------- /模板/12_其他/4_蔡勒公式.tex: -------------------------------------------------------------------------------- 1 | $w = \left(y+\left[\frac {y}{4}\right] + \left[\frac {c}{4}\right] - 2c + \left[\frac{26(m+1)} {10}\right] + d-1 \right) \mod 7$ \\ 2 | 若要计算的日期是在1582年10月4日或之前,公式则为:\\ 3 | $w = \left(y+\left[\frac {y}{4}\right] + \left[\frac {c}{4}\right] - 2c + \left[\frac{26(m+1)} {10}\right] + d+2 \right) \mod 7$ \\ 4 | 公式中的符号含义如下:\\ 5 | w:星期(计算所得的数值对应的星期:0-星期日;1-星期一;2-星期二;3-星期三;4-星期四;5-星期五;6-星期六)\\ 6 | c:年份前两位数\\ 7 | y:年份后两位数\\ 8 | m:月(m的取值范围为3至14,即在蔡勒公式中,某年的1、2月要看作上一年的13、14月来计算,比如2003年1月1日要看作2002年的13月1日来计算)\\ 9 | d:日\\ 10 | (因罗马教宗额我略十三世颁布新历法(公历),把1582年10月4日的后一天改为1582年10月15日)\\ -------------------------------------------------------------------------------- /模板/12_其他/5_坐标旋转变换.cpp: -------------------------------------------------------------------------------- 1 | void rotate(int &x,int &y,int &n,int &m,int t) 2 | { 3 | t%=4; 4 | while(t--) 5 | { 6 | swap(x,y); 7 | y=n-y+1; 8 | swap(n,m); 9 | } 10 | } 11 | 12 | void rotate(int &x,int &y,int &n,int &m,int t) 13 | { 14 | int a,b; 15 | if (t==1) 16 | a=y,b=n-x+1; 17 | if (t==2) 18 | a=n-x+1,b=m-y+1; 19 | if (t==3) 20 | a=m-y+1,b=x; 21 | if (t) x=a,y=b; 22 | if (t&&t!=2) swap(n,m); 23 | } 24 | -------------------------------------------------------------------------------- /模板/12_其他/5_坐标旋转变换.tex: -------------------------------------------------------------------------------- 1 | 要注意在处理多个点的时候,$n$和$m$要存副本。 -------------------------------------------------------------------------------- /模板/12_其他/6_归并排序求逆序数.cpp: -------------------------------------------------------------------------------- 1 | int a[500005],b[500005]; 2 | long long mergesort(int left,int right) 3 | { 4 | if (left==right) 5 | return 0; 6 | long long cnt=0; 7 | int mid=(left+right)/2; 8 | cnt=mergesort(left,mid)+mergesort(mid+1,right); 9 | int i=left,j=mid+1,k=left; 10 | while(i<=mid&&j<=right) 11 | if(a[i]<=a[j]) 12 | b[k++]=a[i++]; 13 | else 14 | { 15 | b[k++]=a[j++]; 16 | cnt+=(mid-i+1); 17 | } 18 | while(i<=mid) 19 | b[k++]=a[i++]; 20 | while(j<=right) 21 | b[k++]=a[j++]; 22 | for(i=left; i<=right; i++) 23 | a[i]=b[i]; 24 | return cnt; 25 | } 26 | -------------------------------------------------------------------------------- /模板/12_其他/7_奇怪的东西.tex: -------------------------------------------------------------------------------- 1 | 格式化html标签 2 | \lstinputlisting{"./模板/12_其他/7_奇怪的东西/1_格式化html标签.cpp"} 3 | 输出数字的英文表示 4 | \lstinputlisting{"./模板/12_其他/7_奇怪的东西/2_输出数字的英文表示.cpp"} 5 | -------------------------------------------------------------------------------- /模板/12_其他/7_奇怪的东西/1_格式化html标签.cpp: -------------------------------------------------------------------------------- 1 | char str[500000]; 2 | inline void jump() 3 | { 4 | char c; 5 | while(isspace(c=getchar())) ; 6 | ungetc(c,stdin); 7 | } 8 | inline string gtag() 9 | { 10 | jump(); 11 | str[0]=0; 12 | scanf("%[^>]",str); 13 | string s=str; 14 | s+=getchar(); 15 | return s; 16 | } 17 | inline void ptag(string &s) 18 | { 19 | puts(s.c_str()); 20 | } 21 | inline string gstr() 22 | { 23 | jump(); 24 | str[0]=0; 25 | scanf("%[^ <\n]",str); 26 | return str; 27 | } 28 | inline void pstr(string &s) 29 | { 30 | printf("%s",s.c_str()); 31 | } 32 | inline int judge(string &s) 33 | { 34 | if (s[1]=='/') return -1; 35 | int flag=0; 36 | for (int i=0; i"; 51 | } 52 | void dostr(int k) 53 | { 54 | string s=gstr(); 55 | if (s!="") 56 | { 57 | pspace(k); 58 | pstr(s); 59 | while(1) 60 | { 61 | s=gstr(); 62 | if (s=="") break; 63 | putchar(' '); 64 | pstr(s); 65 | } 66 | puts(""); 67 | } 68 | } 69 | void solve() 70 | { 71 | int k=0,x; 72 | while(1) 73 | { 74 | string s=gtag(); 75 | x=judge(s); 76 | if (x==-1) pspace(k-1); 77 | else pspace(k); 78 | k+=x; 79 | if (ishtml(s)) 80 | { 81 | ptag(s); 82 | break; 83 | } 84 | ptag(s); 85 | dostr(k); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /模板/12_其他/7_奇怪的东西/2_输出数字的英文表示.cpp: -------------------------------------------------------------------------------- 1 | char a[50][15]= {"","one","two","three","four","five","six","seven","eight","nine","ten","eleven","twelve","thirteen","fourteen","fifteen","sixteen","seventeen","eighteen","nineteen","twenty"}; 2 | char b[50][15]= {"","ten","twenty","thirty","forty","fifty","sixty","seventy","eighty","ninety"}; 3 | char c[50][15]= {"","thousand","million","billion"}; 4 | void gao(int n) 5 | { 6 | int t=n/100,t1=n/10%10,t2=n%10,t3=n%100; 7 | if (t) printf("%s hundred",a[t]); 8 | if (t3) 9 | { 10 | if (t) printf(" and "); 11 | if (t3<=20) printf("%s",a[t3]); 12 | else 13 | { 14 | printf("%s",b[t3/10]); 15 | if (t2) printf("-%s",a[t2]); 16 | } 17 | } 18 | } 19 | int main() 20 | { 21 | int n; 22 | while(scanf("%d",&n),n!=-1) 23 | { 24 | if (n==0) 25 | { 26 | puts("zero"); 27 | continue; 28 | } 29 | int q[5]; 30 | int x=-1; 31 | while(n) q[++x]=n%1000,n/=1000; 32 | for (int i=x; i>=0; i--) 33 | if (q[i]) 34 | { 35 | gao(q[i]); 36 | if (i) printf(" %s",c[i]); 37 | int flag=0; 38 | for (int j=i-1; j>=0; j--) 39 | if (q[j]) flag=1; 40 | if (flag) printf(", "); 41 | } 42 | puts(""); 43 | } 44 | return 0; 45 | } 46 | -------------------------------------------------------------------------------- /模板/12_其他/8_方向数组.cpp: -------------------------------------------------------------------------------- 1 | int dx[]= {0,0,0,-1,1,-1,1,-1,1}; 2 | int dy[]= {0,1,-1,0,0,1,1,-1,-1}; 3 | -------------------------------------------------------------------------------- /模板/13_一些题目.tex: -------------------------------------------------------------------------------- 1 | \section{一些题目} 2 | 3 | \input ./模板/13_一些题目/1.tex 4 | \lstinputlisting{"./模板/13_一些题目/1_1.cpp"} 5 | \lstinputlisting{"./模板/13_一些题目/1_2.cpp"} 6 | 7 | \input ./模板/13_一些题目/2.tex 8 | \lstinputlisting{"./模板/13_一些题目/2.cpp"} 9 | 10 | \input ./模板/13_一些题目/3.tex 11 | \lstinputlisting{"./模板/13_一些题目/3.cpp"} 12 | 13 | 一个次短路问题。题目是要求最短路和比最短路距离长1的次短路的个数。 14 | \lstinputlisting{"./模板/13_一些题目/4.cpp"} 15 | 16 | \begin{center} 17 | \includegraphics[scale=1]{./模板/13_一些题目/5.jpg} 18 | \end{center} 19 | \lstinputlisting{"./模板/13_一些题目/5.cpp"} 20 | -------------------------------------------------------------------------------- /模板/13_一些题目/1.tex: -------------------------------------------------------------------------------- 1 | Description \\ 2 | M公司是一个非常庞大的跨国公司,在许多国家都设有它的下属分支机构或部门。为了让分布在世界各地的N个部门之间协同工作,公司搭建了一个连接整个公司的通信网络。该网络的结构由N个路由器和N-1条高速光缆组成。每个部门都有一个专属的路由器,部门局域网内的所有机器都联向这个路由器,然后再通过这个通信子网与其他部门进行通信联络。该网络结构保证网络中的任意两个路由器之间都存在一条直接或间接路径以进行通信。 高速光缆的数据传输速度非常快,以至于利用光缆传输的延迟时间可以忽略。但是由于路由器老化,在这些路由器上进行数据交换会带来很大的延迟。而两个路由器之间的通信延迟时间则与这两个路由器通信路径上所有路由器中最大的交换延迟时间有关。作为M公司网络部门的一名实习员工,现在要求你编写一个简单的程序来监视公司的网络状况。该程序能够随时更新网络状况的变化信息(路由器数据交换延迟时间的变化),并且根据询问给出两个路由器通信路径上延迟第k大的路由器的延迟时间。【任务】 你的程序从输入文件中读入N个路由器和N-1条光缆的连接信息,每个路由器初始的数据交换延迟时间Ti,以及Q条询问(或状态改变)的信息。并依次处理这Q条询问信息,它们可能是: 1. 由于更新了设备,或者设备出现新的故障,使得某个路由器的数据交换延迟时间发生了变化。 2. 查询某两个路由器a和b之间的路径上延迟第k大的路由器的延迟时间。 \\ 3 | \\ 4 | Input \\ 5 | 第一行为两个整数N和Q,分别表示路由器总数和询问的总数。第二行有N个整数,第i个数表示编号为i的路由器初始的数据延迟时间Ti。紧接着N-1行,每行包含两个整数x和y。表示有一条光缆连接路由器x和路由器y。紧接着是Q行,每行三个整数k、a、b。如果k=0,则表示路由器a的状态发生了变化,它的数据交换延迟时间由Ta变为b。如果k>0,则表示询问a到b的路径上所经过的所有路由器(包括a和b)中延迟第k大的路由器的延迟时间。注意a可以等于b,此时路径上只有一个路由器。 \\ 6 | \\ 7 | Output \\ 8 | 对于每一个第二种询问(k>0),输出一行。包含一个整数为相应的延迟时间。如果路径上的路由器不足k个,则输出信息“invalid request!”(全部小写不包含引号,两个单词之间有一个空格)。 \\ 9 | \\ 10 | Sample Input \\ 11 | 5 5 \\ 12 | 5 1 2 3 4 \\ 13 | 3 1 \\ 14 | 2 1 \\ 15 | 4 3 \\ 16 | 5 3 \\ 17 | 2 4 5 \\ 18 | 0 1 2 \\ 19 | 2 2 3 \\ 20 | 2 1 4 \\ 21 | 3 3 5 \\ 22 | Sample Output \\ 23 | 3 \\ 24 | 2 \\ 25 | 2 \\ 26 | invalid request! \\ 27 | Hint \\ 28 | 10% 测试数据满足N<=8000,Q<=3000, \\ 29 | \\ 30 | 40% 测试数据满足所有询问中1<=K<=5 。即路由器的延迟时间不会发生变化。 \\ 31 | \\ 32 | 100% 测试数据满足N,Q<=80000,任意一个路由器在任何时刻都满足延迟时间小于10^8。对于所有询问满足0<=K<=N 。 \\ 33 | \\ 34 | 一样对树进行划分,对于一条链我们需要支持的操作就是修改一个数,以及查询区间第k大。这是一个经典问题,可以用树套树。具体的说就是链用一个线段树维护,对于线段树中的每个节点,维护当前区间节点的一个平衡树,这样首先内存是NlogN的,然后对于修改,最多涉及到O(logN)个区间,所以复杂度是O(log2N)。对于查询,和普通的区间第k大问题一样,首先二分答案,然后将问题转化成一个判定性问题,从而在区间中查找比这个二分答案小的有几个,复杂度就是O(log3N)。因为一个点到根最多跨越logN条,所以总复杂度就是O(N+Qlog4N)。 35 | -------------------------------------------------------------------------------- /模板/13_一些题目/2.cpp: -------------------------------------------------------------------------------- 1 | for (int i=0; i,则表示若选了i必须选j。 \\ 6 | \\ 7 | 如果我们必须选x,则只需连边即可。因为这样的话如果我们选了x'即不选x,那么我们就必须选x,这就导致了矛盾。所以我们只能选x。 \\ 8 | \\ 9 | 有一对新人结婚,邀请n对夫妇去参加婚礼。有一张很长的桌子,人只能坐在桌子的两边,还要满足下面的要求:1.每对夫妇不能坐在同一侧 2.n对夫妇之中可能有通奸关系(包括男男,男女,女女),有通奸关系的不能同时坐在新娘的对面,可以分开坐,也可以同时坐在新娘这一侧。如果存在一种可行的方案,输出与新娘同侧的人。 \\ 10 | \\ 11 | 所以分成4种情况来建图。1-n的点为h(usband),n+1到2n的点为w(ife)。 12 | -------------------------------------------------------------------------------- /模板/13_一些题目/3.cpp: -------------------------------------------------------------------------------- 1 | typedef int mytype; 2 | const int NV=300005; 3 | const int NE=300005*2; 4 | mytype dis[NV]; 5 | int pre[NV],vis[NV],he[NV],ecnt; 6 | struct edge 7 | { 8 | int v,next; 9 | mytype l; 10 | } E[NE]; 11 | void adde(int u,int v,mytype l) 12 | { 13 | ecnt++; 14 | E[ecnt].v=v; 15 | E[ecnt].l=l; 16 | E[ecnt].next=he[u]; 17 | he[u]=ecnt; 18 | } 19 | void init(int n,int m,int s) 20 | { 21 | for (int i=0; i<=n; i++) 22 | dis[i]=inf; 23 | dis[s]=0; 24 | for (int i=1; i<=m; i++) 25 | { 26 | int u,v; 27 | mytype l; 28 | scanf("%d%d%d",&u,&v,&l); 29 | adde(u,v,l); 30 | adde(v,u,l); 31 | } 32 | } 33 | struct point 34 | { 35 | int u; 36 | mytype l; 37 | point(int a,mytype b):u(a),l(b) {} 38 | bool operator<(const point p) const 39 | { 40 | return l>p.l; 41 | } 42 | }; 43 | void dijkstra_heap(int s) 44 | { 45 | priority_queue q; 46 | q.push(point(s,0)); 47 | while(!q.empty()) 48 | { 49 | point p=q.top(); 50 | q.pop(); 51 | int u=p.u; 52 | if (vis[u]) 53 | continue; 54 | vis[u]=1; 55 | for (int i=he[u]; i!=-1; i=E[i].next) 56 | if (!vis[E[i].v]&&p.l+E[i].l>t; 68 | int cas=0; 69 | while(t--) 70 | { 71 | int n,m,c; 72 | scanf("%d%d%d",&n,&m,&c); 73 | ecnt=0; 74 | memset(pre,0,sizeof(pre)); 75 | memset(vis,0,sizeof(vis)); 76 | memset(he,-1,sizeof(he)); 77 | for (int i=1; i<=n; i++) 78 | { 79 | int x; 80 | scanf("%d",&x); 81 | adde(i,n+x,0); 82 | adde(2*n+x,i,0); 83 | } 84 | for (int i=1; ip.l; 27 | } 28 | }; 29 | int dijkstra_heap(int n,int m,int s,int E) 30 | { 31 | priority_queue q; 32 | q.push(point(s,0,0)); 33 | while(!q.empty()) 34 | { 35 | point p=q.top(); 36 | q.pop(); 37 | int u=p.u; 38 | if (vis[u][p.flag]) 39 | continue; 40 | vis[u][p.flag]=1; 41 | for (int i=he[u]; i!=-1; i=e[i].next) 42 | { 43 | int v=e[i].v; 44 | int dist=p.l+e[i].l; 45 | if (dist>t; 81 | while(t--) 82 | { 83 | int n,m; 84 | scanf("%d%d",&n,&m); 85 | ecnt=0; 86 | memset(he,-1,sizeof(he)); 87 | memset(vis,0,sizeof(vis)); 88 | memset(cnt,0,sizeof(cnt)); 89 | for (int i=1; i<=m; i++) 90 | { 91 | int u,v; 92 | mytype l; 93 | scanf("%d%d%d",&u,&v,&l); 94 | adde(u,v,l); 95 | } 96 | int s,E; 97 | scanf("%d%d",&s,&E); 98 | for (int i=1; i<=n; i++) 99 | dis[i][0]=dis[i][1]=inf; 100 | dis[s][0]=0; 101 | cnt[s][0]=1; 102 | printf("%d\n",dijkstra_heap(n,m,s,E)); 103 | } 104 | return 0; 105 | } 106 | -------------------------------------------------------------------------------- /模板/13_一些题目/5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zheng-fan/ACM-ICPC-Template/d66826512103ef35e1436b68f7ee2201cb3bff09/模板/13_一些题目/5.jpg -------------------------------------------------------------------------------- /模板/1_设置.tex: -------------------------------------------------------------------------------- 1 | \section{设置} 2 | \subsection{头文件} 3 | \lstinputlisting{"./模板/1_设置/1_头文件.cpp"} 4 | 5 | \subsection{Ubuntu相关设置} 6 | \input ./模板/1_设置/2_Ubuntu相关设置.tex 7 | -------------------------------------------------------------------------------- /模板/1_设置/1_头文件.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #define debug puts("-----") 24 | #define pi (acos(-1.0)) 25 | #define eps (1e-8) 26 | #define inf (1<<30) 27 | #define INF (1ll<<62) 28 | using namespace std; 29 | int main() 30 | { 31 | 32 | return 0; 33 | } 34 | -------------------------------------------------------------------------------- /模板/1_设置/2_Ubuntu相关设置.tex: -------------------------------------------------------------------------------- 1 | CodeBlocks终端命令行:\\ 2 | gnome-terminal --disable-factory -t \$TITLE –x\\ 3 | 计算器:\\ 4 | gnome-calculator\\ 5 | xcalc\\ 6 | -------------------------------------------------------------------------------- /模板/2_STL.tex: -------------------------------------------------------------------------------- 1 | \section{STL} 2 | \lstinputlisting{"./模板/2_STL/1_STL.cpp"} 3 | 4 | \input ./模板/2_STL/bitset.tex 5 | -------------------------------------------------------------------------------- /模板/2_STL/1_STL.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * pred可以使用lambda表达式[](args){func_body},需C++11支持 3 | */ 4 | ///欧几里得求最大公约数 5 | __gcd(a,b); 6 | ///对[0,n)建堆 7 | make_heap(a,a+n); 8 | ///将n-1插入到[0,n-1)的堆中 9 | push_heap(a,a+n); 10 | ///将1从[0,n)的堆中取出到n 11 | pop_heap(a,a+n); 12 | ///对[0,n)的堆进行排序 13 | sort_heap(a,a+n); 14 | ///翻转容器内元素 15 | reverse(v.begin(),v.end()); 16 | ///对容器中的key计数 17 | count(v.begin(),v.end(),key); 18 | ///对容器中符合pred条件的元素计数 19 | count_if(v.begin(),v.end(),pred),bool pred(type a); 20 | ///删除容器中值为的key元素,返回end()迭代器 21 | remove(v.begin(),v.end(),key); 22 | v.erase(remove(v.begin(),v.end(),key),v.end()); 23 | ///删除容器中符合pred条件的元素,返回end()迭代器 24 | remove_if(v.begin(),v.end(),pred),bool pred(type a); 25 | ///对容器中元素排重,返回end()迭代器。符合pred的视为相同 26 | unique(v.begin(),v.end()); 27 | unique(v.begin(),v.end(),pred),bool pred(type a,type b); 28 | v.erase(unique(v.begin(),v.end()),v.end()); 29 | ///遍历容器找到值为key元素,返回迭代器,找不到则返回end() 30 | find(v.begin(),v.end(),key); 31 | ///生成下一个全排列,有则返回1,无则返回0 32 | next_permutation(v.begin(),v.end()); 33 | ///生成上一个全排列,有则返回1,无则返回0 34 | prev_permutation(v.begin(),v.end()); 35 | ///可以插入value,而不会破坏容器顺序的第一个位置(插入后其和其后数后移)。指向键值>=key的第一个元素 36 | lower_bound(v.begin(),v.end(),key); 37 | ///可以插入value,而不会破坏容器顺序的最后一个位置(插入后其和其后数后移)。指向键值>key的第一个元素 38 | upper_bound(v.begin(),v.end(),key); 39 | ///将容器内元素按pred条件分开,pred为1的在前,返回分开处end()迭代器 40 | partition(v.begin(),v.end(),pred),bool pred(type a); 41 | stable_partition(v.begin(),v.end(),pred),bool pred(type a); 42 | ///求两个容器内积,返回sum+内积 43 | inner_product(v1.begin(),v1.end(),v2.begin(),sum); 44 | ///对容器内元素求和,返回sum+和 45 | accumulate(v.begin(),v.end(),sum); 46 | ///返回容器内元素的最大/最小值 47 | max_element(v.begin(),v.end()); 48 | min_element(v.begin(),v.end()); 49 | ///重新排列容器内的元素,找到第n小的元素,并把它放在iter_of_nth的位置上,使得在它之前没有大于它的元素,在它之后没有小于它的元素(iter_of_nth隐含着n的值) 50 | nth_element(v.begin(),iter_of_nth,v.end()); 51 | ///将容器内元素都赋值为key 52 | fill(v.begin(),v.end(),key); 53 | ///复制容器v1到v2 54 | copy(v1.begin(),v1.end(),v2.begin()); 55 | ///按字典序比较两个容器 56 | lexicographical_compare(v1.begin(),v1.end(),v2.begin(),v2.end()); 57 | ///合并两个有序容器v1、v2到v,v1与v2可以相同 58 | merge(v1.begin(),v1.end(),v2.begin(),v2.end(),v.begin()); 59 | ///就地合并有序容器[__first,__middle) [__middle,__last) 60 | inplace_merge(__first,__middle,__last); 61 | ///交换区间 [__first,__middle) [__middle,__last) 62 | rotate(__first,__middle,__last); 63 | ///打乱容器内元素的排列顺序 64 | random_shuffle(v.begin(),v.end()); 65 | ///计算前缀和,src可以等于dst:dst[0] = src[0], dst[i] = dst[i - 1] + src[i]; 66 | partial_sum(src,src+n,dst); 67 | ///计算差分,src可以等于dst:dst[0] = src[0], dst[i] = src[i] - src[i - 1]; 68 | adjacent_difference(src,src+n,dst); 69 | ///将字符串以base进制转换成long,并通过ed得到一个char *指向后面未被识别的第一个字符 70 | long strtol(const char *s, char **ed, int base); 71 | ///将字符串str1用str2中的字符分隔开。第一次调用传入str1,以后传入NULL。全部分隔完时返回NULL 72 | char *strtok(char *str1, const char *str2); 73 | /** 74 | char str[] = "now # is the $time for all # good men to co$$me to the # aid of the$ir country"; 75 | char delims[] = "#$"; 76 | char *result = NULL; 77 | result = strtok(str, delims); 78 | while(result != NULL) 79 | { 80 | printf("result is \"%s\"\n", result); 81 | result = strtok(NULL, delims); 82 | } 83 | 运行结果: 84 | result is "now " 85 | result is " is the " 86 | result is "time for all " 87 | result is " good men to co" 88 | result is "me to the " 89 | result is " aid of the" 90 | result is "ir country" 91 | **/ 92 | -------------------------------------------------------------------------------- /模板/2_STL/bitset.tex: -------------------------------------------------------------------------------- 1 | \begin{table}[!htbp] 2 | \centering 3 | \begin{tabular}{|l|l|} 4 | \hline 5 | bitset b; & b有n位,每位都为0 \\ \hline 6 | bitset b(u); & b是unsigned long型u的一个副本 \\ \hline 7 | bitset b(s); & b是string对象s中含有的位串的副本 \\ \hline 8 | bitset b(s, pos, n); & b是s中从位置pos开始的n个位的副本 \\ \hline 9 | \end{tabular} 10 | \end{table} 11 | 12 | \begin{table}[!htbp] 13 | \centering 14 | \begin{tabular}{|l|l|} 15 | \hline 16 | b.any() & b中是否存在置为1的二进制位? \\ \hline 17 | b.none() & b中不存在置为1的二进制位吗? \\ \hline 18 | b.count() & b中置为1的二进制位的个数 \\ \hline 19 | b.size() & b中二进制位的个数 \\ \hline 20 | b[pos] & 访问b中在pos处的二进制位 \\ \hline 21 | b.test(pos) & b中在pos处的二进制位是否为1? \\ \hline 22 | b.set() & 把b中所有二进制位都置为1 \\ \hline 23 | b.set(pos) & 把b中在pos处的二进制位置为1 \\ \hline 24 | b.reset() & 把b中所有二进制位都置为0 \\ \hline 25 | b.reset(pos) & 把b中在pos处的二进制位置为0 \\ \hline 26 | b.flip() & 把b中所有二进制位逐位取反 \\ \hline 27 | b.flip(pos) & 把b中在pos处的二进制位取反 \\ \hline 28 | b.to\_ulong() & 用b中同样的二进制位返回一个unsigned long值 \\ \hline 29 | os << b & 把b中的位集输出到os流 \\ \hline 30 | \end{tabular} 31 | \end{table} 32 | -------------------------------------------------------------------------------- /模板/3_基本算法.tex: -------------------------------------------------------------------------------- 1 | \section{基本算法} 2 | \subsection{二分} 3 | \lstinputlisting{"./模板/3_基本算法/1_二分.cpp"} 4 | 5 | \subsection{三分} 6 | \lstinputlisting{"./模板/3_基本算法/2_三分.cpp"} 7 | -------------------------------------------------------------------------------- /模板/3_基本算法/1_二分.cpp: -------------------------------------------------------------------------------- 1 | ///二分(单调增) 2 | double l=0,r=100,mid; 3 | while(r-l>eps) 4 | { 5 | mid=(l+r)/2; 6 | if (f(mid)>0) 7 | r=mid; 8 | else 9 | l=mid; 10 | } 11 | 12 | ///二分(精确binary_search) 13 | int l=0,r=10000,mid; 14 | while(l<=r) 15 | { 16 | mid=l+r>>1; 17 | if (a[mid]>key) 18 | r=mid-1; 19 | else if (a[mid]>1; 31 | if (a[mid]>=key) 32 | r=mid; 33 | else if (a[mid]eps) 6 | { 7 | mid1=(left+right)/2; 8 | mid2=(mid1+right)/2; 9 | if (f(mid1) r) return; 26 | int mid = l + r >> 1; 27 | int minX, minY, maxX, maxY; 28 | minX = min_element(p + l, p + r + 1, cmpX)->x; 29 | minY = min_element(p + l, p + r + 1, cmpY)->y; 30 | maxX = max_element(p + l, p + r + 1, cmpX)->x; 31 | maxY = max_element(p + l, p + r + 1, cmpY)->y; 32 | Div[mid] = (maxX - minX >= maxY - minY); 33 | nth_element(p + l, p + mid, p + r + 1, Div[mid] ? cmpX : cmpY); 34 | build(l, mid - 1, p); 35 | build(mid + 1, r, p); 36 | } 37 | void find(long long &res, int l, int r, point &a, point p[]) 38 | { 39 | if (l > r) return; 40 | int mid = l + r >> 1; 41 | long long dist = dis(a, p[mid]); 42 | if (dist > 0) ///NOTICE 43 | res = min(res, dist); 44 | long long d = Div[mid] ? (a.x - p[mid].x) : (a.y - p[mid].y); 45 | int l1, l2, r1, r2; 46 | l1 = l, l2 = mid + 1; 47 | r1 = mid - 1, r2 = r; 48 | if (d > 0) swap(l1, l2), swap(r1, r2); 49 | find(res, l1, r1, a, p); 50 | if (d * d < res) find(res, l2, r2, a, p); 51 | } 52 | long long find(int l,int r, point &a, point p[]) 53 | { 54 | long long res=INF; 55 | find(res,l,r,a,p); 56 | return res; 57 | } 58 | point pp[NV]; 59 | int main() 60 | { 61 | int t; 62 | cin>>t; 63 | while(t--) 64 | { 65 | int n; 66 | cin>>n; 67 | for (int i=1; i<=n; i++) p[i].in(),pp[i]=p[i]; 68 | build(1,n,p); 69 | for (int i=1; i<=n; i++) 70 | printf("%I64d\n",find(1,n,pp[i],p)); 71 | } 72 | return 0; 73 | } 74 | -------------------------------------------------------------------------------- /模板/4_数据结构/11_KD-tree/HDU4347.cpp: -------------------------------------------------------------------------------- 1 | #define sqr(x) (x)*(x) 2 | const int NV=50005,K=5; 3 | //k为维数,n为点数,idx为当前比较的维度 4 | int k,n,idx; 5 | struct point 6 | { 7 | int x[K]; 8 | bool operator <(const point &u) const 9 | { 10 | return x[idx] >nq; 14 | //线段树节点 15 | point pt[NV<<2]; 16 | int son[NV<<2]; 17 | void build(int l,int r,int rt=1,int dep=0) 18 | { 19 | if(l>r) return; 20 | son[rt]=r-l; 21 | son[rt<<1]=son[rt<<1|1]=-1; 22 | idx=dep%k; 23 | int mid=l+r>>1; 24 | nth_element(po+l,po+mid,po+r+1); 25 | pt[rt]=po[mid]; 26 | build(l,mid-1,rt<<1,dep+1); 27 | build(mid+1,r,rt<<1|1,dep+1); 28 | } 29 | void query(point &p,int m,int rt=1,int dep=0) 30 | { 31 | if(son[rt]==-1) return; 32 | pair nd(0,pt[rt]); 33 | for(int i=0; i=pt[rt].x[dim]) swap(x,y); 36 | if(~son[x]) query(p,m,x,dep+1); 37 | if(nq.size()=1; i--) 71 | for(int j=0; jsiz[son[u]]) 24 | son[u]=v; 25 | } 26 | } 27 | } 28 | void dfs2(int u,int tp) 29 | { 30 | top[u]=tp; 31 | w[u]=++tot; 32 | rank[w[u]]=u; 33 | if(son[u]==-1) return; 34 | dfs2(son[u],tp); 35 | for(int i=he[u]; ~i; i=next[i]) 36 | { 37 | int v=to[i]; 38 | if(v!=son[u]&&v!=fa[u]) 39 | dfs2(v,v); 40 | } 41 | } 42 | #define lson l,m,rt<<1 43 | #define rson m+1,r,rt<<1|1 44 | int add[NV<<2],sum[NV<<2]; 45 | void PushUp(int rt) 46 | { 47 | sum[rt]=sum[rt<<1]+sum[rt<<1|1]; 48 | } 49 | void PushDown(int rt,int m) 50 | { 51 | if (add[rt]) 52 | { 53 | add[rt<<1] += add[rt]; 54 | add[rt<<1|1] += add[rt]; 55 | sum[rt<<1] += add[rt] * (m - (m >> 1)); 56 | sum[rt<<1|1] += add[rt] * (m >> 1); 57 | add[rt] = 0; 58 | } 59 | } 60 | void build(int l,int r,int rt=1) 61 | { 62 | add[rt] = 0; 63 | if (l == r) 64 | { 65 | sum[rt]=num[rank[l]]; 66 | return ; 67 | } 68 | int m = (l + r) >> 1; 69 | build(lson); 70 | build(rson); 71 | PushUp(rt); 72 | } 73 | void update(int L,int R,int c,int l,int r,int rt=1) 74 | { 75 | if (L <= l && r <= R) 76 | { 77 | add[rt] += c; 78 | sum[rt] += c * (r - l + 1); 79 | return ; 80 | } 81 | PushDown(rt, r - l + 1); 82 | int m = (l + r) >> 1; 83 | if (L <= m) update(L, R, c, lson); 84 | if (m < R) update(L, R, c, rson); 85 | PushUp(rt); 86 | } 87 | int query(int L,int l,int r,int rt=1) 88 | { 89 | if (L == l && l == r) 90 | { 91 | return sum[rt]; 92 | } 93 | PushDown(rt, r - l + 1); 94 | int m = (l + r) >> 1; 95 | if (L <= m) return query(L, lson); 96 | return query(L, rson); 97 | } 98 | void change(int x,int y,int l,int r,int c) 99 | { 100 | while(top[x]!=top[y]) 101 | { 102 | if(dep[top[x]]dep[y]) swap(x,y); 107 | update(w[x],w[y],c,l,r); 108 | } 109 | void init(int n) 110 | { 111 | memset(he,-1,sizeof(he)); 112 | memset(son,-1,sizeof(son)); 113 | tot=0; 114 | ecnt=0; 115 | for(int i=1; i<=n; i++) 116 | scanf("%d",&num[i]); 117 | for(int i=1; isiz[son[u]]) 24 | son[u]=v; 25 | } 26 | } 27 | } 28 | void dfs2(int u,int tp) 29 | { 30 | top[u]=tp; 31 | w[u]=++tot; 32 | rank[w[u]]=u; 33 | if(son[u]==-1) return; 34 | dfs2(son[u],tp); 35 | for(int i=he[u]; ~i; i=next[i]) 36 | { 37 | int v=to[i]; 38 | if(v!=son[u]&&v!=fa[u]) 39 | dfs2(v,v); 40 | } 41 | } 42 | #define lson l,m,rt<<1 43 | #define rson m+1,r,rt<<1|1 44 | int sum[NV<<2]; 45 | void PushUp(int rt) 46 | { 47 | sum[rt]=sum[rt<<1]+sum[rt<<1|1]; 48 | } 49 | void build(int l,int r,int rt=1) 50 | { 51 | if (l == r) 52 | { 53 | sum[rt]=num[l]; 54 | return ; 55 | } 56 | int m = (l + r) >> 1; 57 | build(lson); 58 | build(rson); 59 | PushUp(rt); 60 | } 61 | void update(int L,int c,int l,int r,int rt=1) 62 | { 63 | if (L == l && l == r) 64 | { 65 | sum[rt] = c; 66 | return ; 67 | } 68 | int m = (l + r) >> 1; 69 | if (L <= m) update(L, c, lson); 70 | else update(L, c, rson); 71 | PushUp(rt); 72 | } 73 | int query(int L,int R,int l,int r,int rt=1) 74 | { 75 | if (L <= l && r <= R) 76 | { 77 | return sum[rt]; 78 | } 79 | int m = (l + r) >> 1; 80 | int ret = 0; 81 | if (L <= m) ret += query(L, R, lson); 82 | if (m < R) ret += query(L, R, rson); 83 | return ret; 84 | } 85 | int getsum(int x,int y,int l,int r) 86 | { 87 | int ret=0; 88 | while(top[x]!=top[y]) 89 | { 90 | if(dep[top[x]]dep[y]) swap(x,y); 96 | ret+=query(w[son[x]],w[y],l,r); ///Notice! 比点权多了个son 97 | return ret; 98 | } 99 | int uu[NV],vv[NV],ll[NV]; 100 | void init(int n) 101 | { 102 | memset(he,-1,sizeof(he)); 103 | memset(son,-1,sizeof(son)); 104 | tot=0; 105 | ecnt=0; 106 | for(int i=1; irk[b]) f[b]=a; 27 | else 28 | { 29 | if (rk[a]==rk[b]) rk[b]++; 30 | f[a]=b; 31 | } 32 | } 33 | void init(int n) 34 | { 35 | memset(rk,0,sizeof(rk)); 36 | for (int i=1; i<=n; i++) 37 | f[i]=i; 38 | } 39 | -------------------------------------------------------------------------------- /模板/4_数据结构/3_树状数组.tex: -------------------------------------------------------------------------------- 1 | \subsection{树状数组} 2 | \subsubsection{一维树状数组} 3 | \lstinputlisting{"./模板/4_数据结构/3_树状数组/1_一维树状数组.cpp"} 4 | 5 | \subsubsection{一维树状数组区间更新区间查询} 6 | \lstinputlisting{"./模板/4_数据结构/3_树状数组/2_一维树状数组区间更新区间查询.cpp"} 7 | 8 | \subsubsection{多维树状数组的处理} 9 | \lstinputlisting{"./模板/4_数据结构/3_树状数组/3_多维树状数组的处理.cpp"} 10 | -------------------------------------------------------------------------------- /模板/4_数据结构/3_树状数组/1_一维树状数组.cpp: -------------------------------------------------------------------------------- 1 | int N; 2 | const int NV=500005; 3 | int c[NV]; 4 | inline int lowbit(int t) 5 | { 6 | return t&(-t); 7 | } 8 | void update(int x,int v) 9 | { 10 | while(x<=N) 11 | { 12 | c[x]+=v; 13 | x+=lowbit(x); 14 | } 15 | } 16 | int query(int x) 17 | { 18 | int ans=0; 19 | while(x>0) 20 | { 21 | ans+=c[x]; 22 | x-=lowbit(x); 23 | } 24 | return ans; 25 | } 26 | ///要注意k超过了树状数组中元素总和的情况 27 | int findkth(int k) 28 | { 29 | int idx = 0; 30 | for(int i=20; i>=0; i--) 31 | { 32 | idx |= 1 << i; 33 | if(idx <= N && c[idx] < k) 34 | k -= c[idx]; 35 | else idx ^= 1 << i; 36 | } 37 | return idx + 1; 38 | } 39 | -------------------------------------------------------------------------------- /模板/4_数据结构/3_树状数组/2_一维树状数组区间更新区间查询.cpp: -------------------------------------------------------------------------------- 1 | int N; 2 | const int NV=500005; 3 | long long c[NV],b[NV]; 4 | inline int lowbit(int t) 5 | { 6 | return t&(-t); 7 | } 8 | void update(long long c[],int flag,int x,long long v) 9 | { 10 | if (flag) for (int i=x; i<=N; i+=lowbit(i)) c[i]+=x*v; 11 | else for (int i=x; i>0; i-=lowbit(i)) c[i]+=v; 12 | } 13 | long long query(long long c[],int flag,int x) 14 | { 15 | long long ans=0; 16 | if (flag) for (int i=x; i>0; i-=lowbit(i)) ans+=c[i]; 17 | else for (int i=x; i<=N; i+=lowbit(i)) ans+=c[i]; 18 | return ans; 19 | } 20 | void add(int l,int r,long long v) 21 | { 22 | update(b,0,r,v); 23 | update(c,1,r,v); 24 | if (l>1) 25 | { 26 | update(b,0,l-1,-v); 27 | update(c,1,l-1,-v); 28 | } 29 | } 30 | long long sum(int x) 31 | { 32 | if (x) return query(b,0,x)*x+query(c,1,x-1); 33 | else return 0; 34 | } 35 | long long sum(int l,int r) 36 | { 37 | return sum(r)-sum(l-1); 38 | } 39 | -------------------------------------------------------------------------------- /模板/4_数据结构/3_树状数组/3_多维树状数组的处理.cpp: -------------------------------------------------------------------------------- 1 | int N; 2 | int c[2005][2005]; 3 | inline int lowbit(int t) 4 | { 5 | return t&(-t); 6 | } 7 | void update(int x,int y,int v) 8 | { 9 | for (int i=x; i<=N; i+=lowbit(i)) 10 | for (int j=y; j<=N; j+=lowbit(j)) 11 | c[i][j]+=v; 12 | } 13 | int query(int x,int y) 14 | { 15 | int s=0; 16 | for (int i=x; i>0; i-=lowbit(i)) 17 | for (int j=y; j>0; j-=lowbit(j)) 18 | s+=c[i][j]; 19 | return s; 20 | } 21 | int sum(int x,int y,int xx,int yy) 22 | { 23 | x--,y--; 24 | return query(xx,yy)-query(xx,y)-query(x,yy)+query(x,y); 25 | } 26 | 27 | int N; 28 | long long c[130][130][130]= {}; 29 | inline int lowbit(int t) 30 | { 31 | return t&(-t); 32 | } 33 | void update(int x,int y,int z,long long v) 34 | { 35 | for (int i=x; i<=N; i+=lowbit(i)) 36 | for (int j=y; j<=N; j+=lowbit(j)) 37 | for (int k=z; k<=N; k+=lowbit(k)) 38 | c[i][j][k]+=v; 39 | } 40 | long long query(int x,int y,int z) 41 | { 42 | long long s=0; 43 | for (int i=x; i>0; i-=lowbit(i)) 44 | for (int j=y; j>0; j-=lowbit(j)) 45 | for (int k=z; k>0; k-=lowbit(k)) 46 | s+=c[i][j][k]; 47 | return s; 48 | } 49 | long long sum(int x,int y,int z,int xx,int yy,int zz) 50 | { 51 | x--,y--,z--; 52 | return query(xx,yy,zz) 53 | -query(x,yy,zz)-query(xx,y,zz)-query(xx,yy,z) 54 | +query(x,y,zz)+query(xx,y,z)+query(x,yy,z) 55 | -query(x,y,z); 56 | } 57 | -------------------------------------------------------------------------------- /模板/4_数据结构/4_RMQ.tex: -------------------------------------------------------------------------------- 1 | \subsection{RMQ} 2 | \subsubsection{一维RMQ} 3 | \lstinputlisting{"./模板/4_数据结构/4_RMQ/1_一维RMQ.cpp"} 4 | 5 | \subsubsection{二维RMQ} 6 | \lstinputlisting{"./模板/4_数据结构/4_RMQ/2_二维RMQ.cpp"} 7 | -------------------------------------------------------------------------------- /模板/4_数据结构/4_RMQ/1_一维RMQ.cpp: -------------------------------------------------------------------------------- 1 | const int NV=50005; 2 | const int NVB=20; 3 | int mx[NVB][NV],mn[NVB][NV],a[NV]; 4 | void init(int data[],int n) 5 | { 6 | int k=log2(n); 7 | for (int i=1; i<=n; i++) 8 | mx[0][i]=mn[0][i]=data[i]; 9 | for (int i=1; i<=k; i++) 10 | for (int j=1; j+(1<>1)]); 13 | mn[i][j]=min(mn[i-1][j],mn[i-1][j+(1<>1)]); 14 | } 15 | } 16 | int query(int l,int r,int flag) 17 | { 18 | int k=log2(r-l+1); 19 | if (flag) return max(mx[k][l],mx[k][r-(1<>1)]); 14 | mn[k][i][j]=min(mn[k-1][i][j],mn[k-1][i][j+(1<>1)]); 15 | } 16 | } 17 | ///行,列,矩阵宽度 18 | void query(int row,int col,int b) 19 | { 20 | int k=log2(b); 21 | mxt=-1; 22 | mnt=inf; 23 | int l=col,r=col+b-1; 24 | for(int i=row; i> 1; 17 | build(lson); 18 | build(rson); 19 | PushUp(rt); 20 | } 21 | void update(int L,int c,int l,int r,int rt=1) 22 | { 23 | if (L == l && l == r) 24 | { 25 | sum[rt] += c; 26 | return ; 27 | } 28 | int m = (l + r) >> 1; 29 | if (L <= m) update(L, c, lson); 30 | else update(L, c, rson); 31 | PushUp(rt); 32 | } 33 | int query(int L,int R,int l,int r,int rt=1) 34 | { 35 | if (L <= l && r <= R) 36 | return sum[rt]; 37 | int m = (l + r) >> 1; 38 | int ret = 0; 39 | if (L <= m) ret += query(L, R, lson); 40 | if (m < R) ret += query(L, R, rson); 41 | return ret; 42 | } 43 | -------------------------------------------------------------------------------- /模板/4_数据结构/5_线段树/2_区间更新.cpp: -------------------------------------------------------------------------------- 1 | #define lson l,m,rt<<1 2 | #define rson m+1,r,rt<<1|1 3 | const int NV = 100005; 4 | int add[NV<<2],sum[NV<<2]; 5 | void PushUp(int rt) 6 | { 7 | sum[rt]=sum[rt<<1]+sum[rt<<1|1]; 8 | } 9 | void PushDown(int rt,int m) 10 | { 11 | if (add[rt]) 12 | { 13 | add[rt<<1] += add[rt]; 14 | add[rt<<1|1] += add[rt]; 15 | sum[rt<<1] += add[rt] * (m - (m >> 1)); 16 | sum[rt<<1|1] += add[rt] * (m >> 1); 17 | add[rt] = 0; 18 | } 19 | } 20 | void build(int l,int r,int rt=1) 21 | { 22 | add[rt] = 0; 23 | if (l == r) 24 | { 25 | sum[rt]=0; 26 | return ; 27 | } 28 | int m = (l + r) >> 1; 29 | build(lson); 30 | build(rson); 31 | PushUp(rt); 32 | } 33 | void update(int L,int R,int c,int l,int r,int rt=1) 34 | { 35 | if (L <= l && r <= R) 36 | { 37 | add[rt] += c; 38 | sum[rt] += c * (r - l + 1); 39 | return ; 40 | } 41 | PushDown(rt, r - l + 1); 42 | int m = (l + r) >> 1; 43 | if (L <= m) update(L, R, c, lson); 44 | if (m < R) update(L, R, c, rson); 45 | PushUp(rt); 46 | } 47 | int query(int L,int R,int l,int r,int rt=1) 48 | { 49 | if (L <= l && r <= R) 50 | { 51 | return sum[rt]; 52 | } 53 | PushDown(rt, r - l + 1); 54 | int m = (l + r) >> 1; 55 | int ret = 0; 56 | if (L <= m) ret += query(L, R, lson); 57 | if (m < R) ret += query(L, R, rson); 58 | return ret; 59 | } 60 | -------------------------------------------------------------------------------- /模板/4_数据结构/5_线段树/3_对一棵树进行线段树操作.cpp: -------------------------------------------------------------------------------- 1 | const int NV=10005; 2 | const int NE=NV; 3 | int he[NV],ecnt; 4 | struct edge 5 | { 6 | int v,next; 7 | } E[NE]; 8 | void adde(int u,int v) 9 | { 10 | ecnt++; 11 | E[ecnt].v=v; 12 | E[ecnt].next=he[u]; 13 | he[u]=ecnt; 14 | } 15 | int l[NV],r[NV],p; 16 | void dfs(int u) 17 | { 18 | p++; 19 | l[u]=p; 20 | for (int i=he[u]; i!=-1; i=E[i].next) 21 | dfs(E[i].v); 22 | r[u]=p; 23 | } 24 | void init() 25 | { 26 | ecnt=p=0; 27 | memset(he,-1,sizeof(he)); 28 | } 29 | -------------------------------------------------------------------------------- /模板/4_数据结构/5_线段树/4_二维线段树区间更新单点求和.cpp: -------------------------------------------------------------------------------- 1 | const int NV=1005; 2 | struct Nodey 3 | { 4 | int l,r; 5 | int val; 6 | }; 7 | int n; 8 | int locx[NV],locy[NV]; 9 | struct Nodex 10 | { 11 | int l,r; 12 | Nodey sty[NV*3]; 13 | void build(int _l,int _r,int i=1) 14 | { 15 | sty[i].l = _l; 16 | sty[i].r = _r; 17 | sty[i].val = 0; 18 | if(_l == _r) 19 | { 20 | locy[_l] = i; 21 | return; 22 | } 23 | int mid = (_l + _r)>>1; 24 | build(_l,mid,i<<1); 25 | build(mid+1,_r,(i<<1)|1); 26 | } 27 | void add(int _l,int _r,int val,int i=1) 28 | { 29 | if(sty[i].l == _l && sty[i].r == _r) 30 | { 31 | sty[i].val += val; 32 | return; 33 | } 34 | int mid = (sty[i].l + sty[i].r)>>1; 35 | if(_r <= mid)add(_l,_r,val,i<<1); 36 | else if(_l > mid)add(_l,_r,val,(i<<1)|1); 37 | else 38 | { 39 | add(_l,mid,val,i<<1); 40 | add(mid+1,_r,val,(i<<1)|1); 41 | } 42 | } 43 | } stx[NV*3]; 44 | void build(int l,int r,int i=1) 45 | { 46 | stx[i].l = l; 47 | stx[i].r = r; 48 | stx[i].build(1,n); 49 | if(l == r) 50 | { 51 | locx[l] = i; 52 | return; 53 | } 54 | int mid = (l+r)>>1; 55 | build(l,mid,i<<1); 56 | build(mid+1,r,(i<<1)|1); 57 | } 58 | void add(int x1,int x2,int y1,int y2,int val,int i=1) 59 | { 60 | if(stx[i].l == x1 && stx[i].r == x2) 61 | { 62 | stx[i].add(y1,y2,val); 63 | return; 64 | } 65 | int mid = (stx[i].l + stx[i].r)/2; 66 | if(x2 <= mid)add(x1,x2,y1,y2,val,i<<1); 67 | else if(x1 > mid)add(x1,x2,y1,y2,val,(i<<1)|1); 68 | else 69 | { 70 | add(x1,mid,y1,y2,val,i<<1); 71 | add(mid+1,x2,y1,y2,val,(i<<1)|1); 72 | } 73 | } 74 | int sum(int x,int y) 75 | { 76 | int ret = 0; 77 | for(int i = locx[x]; i; i >>= 1) 78 | for(int j = locy[y]; j; j >>= 1) 79 | ret += stx[i].sty[j].val; 80 | return ret; 81 | } 82 | -------------------------------------------------------------------------------- /模板/4_数据结构/5_线段树/5_二维线段树单点更新区间求最大最小值.cpp: -------------------------------------------------------------------------------- 1 | const int NV=1005; 2 | struct Nodey 3 | { 4 | int l,r; 5 | int Max,Min; 6 | }; 7 | int locy[NV],locx[NV]; 8 | struct Nodex 9 | { 10 | int l,r; 11 | Nodey sty[NV*4]; 12 | void build(int _l,int _r,int i=1) 13 | { 14 | sty[i].l = _l; 15 | sty[i].r = _r; 16 | sty[i].Max = -inf; 17 | sty[i].Min = inf; 18 | if(_l == _r) 19 | { 20 | locy[_l] = i; 21 | return; 22 | } 23 | int mid = (_l + _r)/2; 24 | build(_l,mid,i<<1); 25 | build(mid+1,_r,(i<<1)|1); 26 | } 27 | int queryMin(int _l,int _r,int i=1) 28 | { 29 | if(sty[i].l == _l && sty[i].r == _r) 30 | return sty[i].Min; 31 | int mid = (sty[i].l + sty[i].r)/2; 32 | if(_r <= mid)return queryMin(_l,_r,i<<1); 33 | else if(_l > mid)return queryMin(_l,_r,(i<<1)|1); 34 | else return min(queryMin(_l,mid,i<<1),queryMin(mid+1,_r,(i<<1)|1)); 35 | } 36 | int queryMax(int _l,int _r,int i=1) 37 | { 38 | if(sty[i].l == _l && sty[i].r == _r) 39 | return sty[i].Max; 40 | int mid = (sty[i].l + sty[i].r)/2; 41 | if(_r <= mid)return queryMax(_l,_r,i<<1); 42 | else if(_l > mid)return queryMax(_l,_r,(i<<1)|1); 43 | else return max(queryMax(_l,mid,i<<1),queryMax(mid+1,_r,(i<<1)|1)); 44 | } 45 | } stx[NV*4]; 46 | int n; 47 | void build(int l,int r,int i=1) 48 | { 49 | stx[i].l = l; 50 | stx[i].r = r; 51 | stx[i].build(1,n); 52 | if(l == r) 53 | { 54 | locx[l] = i; 55 | return; 56 | } 57 | int mid = (l+r)/2; 58 | build(l,mid,i<<1); 59 | build(mid+1,r,(i<<1)|1); 60 | } 61 | void modify(int x,int y,int val) 62 | { 63 | int tx = locx[x]; 64 | int ty = locy[y]; 65 | stx[tx].sty[ty].Min = stx[tx].sty[ty].Max = val; 66 | for(int i = tx; i; i >>= 1) 67 | for(int j = ty; j; j >>= 1) 68 | { 69 | if(i == tx && j == ty)continue; 70 | if(j == ty) 71 | { 72 | stx[i].sty[j].Min = min(stx[i<<1].sty[j].Min,stx[(i<<1)|1].sty[j].Min); 73 | stx[i].sty[j].Max = max(stx[i<<1].sty[j].Max,stx[(i<<1)|1].sty[j].Max); 74 | } 75 | else 76 | { 77 | stx[i].sty[j].Min = min(stx[i].sty[j<<1].Min,stx[i].sty[(j<<1)|1].Min); 78 | stx[i].sty[j].Max = max(stx[i].sty[j<<1].Max,stx[i].sty[(j<<1)|1].Max); 79 | } 80 | } 81 | } 82 | int queryMin(int x1,int x2,int y1,int y2,int i=1) 83 | { 84 | if(stx[i].l == x1 && stx[i].r == x2) 85 | return stx[i].queryMin(y1,y2); 86 | int mid = (stx[i].l + stx[i].r)/2; 87 | if(x2 <= mid)return queryMin(x1,x2,y1,y2,i<<1); 88 | else if(x1 > mid)return queryMin(x1,x2,y1,y2,(i<<1)|1); 89 | else return min(queryMin(x1,mid,y1,y2,i<<1),queryMin(mid+1,x2,y1,y2,(i<<1)|1)); 90 | } 91 | int queryMax(int x1,int x2,int y1,int y2,int i=1) 92 | { 93 | if(stx[i].l == x1 && stx[i].r == x2) 94 | return stx[i].queryMax(y1,y2); 95 | int mid = (stx[i].l + stx[i].r)/2; 96 | if(x2 <= mid)return queryMax(x1,x2,y1,y2,i<<1); 97 | else if(x1 > mid)return queryMax(x1,x2,y1,y2,(i<<1)|1); 98 | else return max(queryMax(x1,mid,y1,y2,i<<1),queryMax(mid+1,x2,y1,y2,(i<<1)|1)); 99 | } 100 | -------------------------------------------------------------------------------- /模板/4_数据结构/5_线段树/6_线段树相关例题.tex: -------------------------------------------------------------------------------- 1 | \subsubsection{线段树相关例题} 2 | 3 | 单点增加,区间求和 4 | \lstinputlisting{"./模板/4_数据结构/5_线段树/6_线段树相关例题/单点更新/1_HDU1166.cpp"} 5 | 单点修改,区间求最值 6 | \lstinputlisting{"./模板/4_数据结构/5_线段树/6_线段树相关例题/单点更新/2_HDU1754.cpp"} 7 | %单点增加,区间求和(求逆序数) 8 | %\lstinputlisting{"./模板/4_数据结构/5_线段树/6_线段树相关例题/单点更新/3_HDU1394.cpp"} 9 | 单点找最大值$\ge$c的第一个位置,同时单点更新 10 | \lstinputlisting{"./模板/4_数据结构/5_线段树/6_线段树相关例题/单点更新/4_HDU2795.cpp"} 11 | 找第K大数,同时单点更新。(使用sum数组) 12 | \lstinputlisting{"./模板/4_数据结构/5_线段树/6_线段树相关例题/单点更新/5_POJ2828.cpp"} 13 | %找第K大数,同时单点更新。(使用sum数组) 14 | %\lstinputlisting{"./模板/4_数据结构/5_线段树/6_线段树相关例题/单点更新/6_POJ2886.cpp"} 15 | 1、add x表示往集合里添加数x。2、del x表示将集合中数x删除。3、sum求出从小到大排列的集合中下标模$5$为$3$的数的和。集合中的数都是唯一的。\\ 16 | 在线段树中维护当前这个集合中数的个数sum,和所有的数模$5$为$0\cdots4$内的数的和设为ans[$0\cdots4$]。在进行区间合并的时候,父区间里的ans[$0\cdots4$]首先等于左子区间里的ans[$0\cdots4$],设要加入的右子区间的数为ans[i],则它应该加到父区间的ans[sum[rt<<1]+i]。 17 | \lstinputlisting{"./模板/4_数据结构/5_线段树/6_线段树相关例题/单点更新/7_HDU4288.cpp"} 18 | 有三种操作“add x y”往平面上添加(x,y)这个点,“remove x y”,将平面上已经存在的点(x,y)删除,“find x y”找出平面上坐标严格大于(x,y)的点,如果有多个点找x最小的,再找y最小的。\\ 19 | 用线段树维护y的最大值。 20 | \lstinputlisting{"./模板/4_数据结构/5_线段树/6_线段树相关例题/单点更新/8_CF19D.cpp"} 21 | %给你一些区间,问对于给出的每个区间,有多少个区间是完全包含它的。其实就是求逆序数。 22 | %\lstinputlisting{"./模板/4_数据结构/5_线段树/6_线段树相关例题/单点更新/9_POJ2481.cpp"} 23 | %单点增加,求第K大数 24 | %\lstinputlisting{"./模板/4_数据结构/5_线段树/6_线段树相关例题/单点更新/ZOJProblemSet-3612.cpp"} 25 | 26 | 27 | 区间置值,区间求和 28 | \lstinputlisting{"./模板/4_数据结构/5_线段树/6_线段树相关例题/区间更新/1_HDU1698.cpp"} 29 | %区间增加,区间求和 30 | %\lstinputlisting{"./模板/4_数据结构/5_线段树/6_线段树相关例题/区间更新/2_POJ3468.cpp"} 31 | 区间置值,单点询问 32 | \lstinputlisting{"./模板/4_数据结构/5_线段树/6_线段树相关例题/区间更新/3_POJ2528.cpp"} 33 | 区间置值,区间查询有几种值 34 | \lstinputlisting{"./模板/4_数据结构/5_线段树/6_线段树相关例题/区间更新/4_POJ1436.cpp"} 35 | 有N根杆子,前后两根杆子通过一个节点连接,每个节点可以旋转一定的角度,每次给你一个操作(s,a)表示将第S与S+1之间的角度修改为a度,并且每次操作之后都需要求出第N个节点的位置。\\ 36 | 首先,最后一个节点的坐标(即位置)可以通过所有杆子末尾的坐标相加得到(这跟向量相加很类似)。因为每次更新需要修改S和S+1的位置,所以我们需要知道每次更新之后S和S+1的角度——查询操作,知道之后,再根据这次需要修改的角度a,得到S+1到最后一段杆子需要改变的角度——更新操作。最后输出答案即所有节点的x坐标和,y坐标和。\\ 37 | add为ang增加的lazy标记,ang记录杆子末尾的角度,每次更新前query角度,就可以知道此次更新的角度的相对值,从而修改坐标x,y。 38 | \lstinputlisting{"./模板/4_数据结构/5_线段树/6_线段树相关例题/区间更新/5_POJ2991.cpp"} 39 | 给定n长的序列 m个操作\\ 40 | 序列默认为 1, 2, 3...n\\ 41 | 操作1:D [l,r] 把[l,r]区间增长 :( 1,2,3,4 进行 D [1,3]变成 1,1,2,2,3,3,4 )\\ 42 | 操作2:Q [l,r] 问区间[l,r] 上出现最多次数的数的次数\\ 43 | 区间乘积,单点增加,区间求最值,找第K大数 44 | \lstinputlisting{"./模板/4_数据结构/5_线段树/6_线段树相关例题/区间更新/HDU4973.cpp"} 45 | 区间更新最值,单点查询最值 46 | \lstinputlisting{"./模板/4_数据结构/5_线段树/6_线段树相关例题/区间更新/ZOJProblemSet-3632.cpp"} 47 | -------------------------------------------------------------------------------- /模板/4_数据结构/5_线段树/6_线段树相关例题/区间更新/1_HDU1698.cpp: -------------------------------------------------------------------------------- 1 | #define lson l,m,rt<<1 2 | #define rson m+1,r,rt<<1|1 3 | const int NV = 100005; 4 | int stt[NV<<2],sum[NV<<2]; 5 | void PushUp(int rt) 6 | { 7 | sum[rt]=sum[rt<<1]+sum[rt<<1|1]; 8 | } 9 | void PushDown(int rt,int m) 10 | { 11 | if (stt[rt]) 12 | { 13 | stt[rt<<1] = stt[rt]; 14 | stt[rt<<1|1] = stt[rt]; 15 | sum[rt<<1] = stt[rt] * (m - (m >> 1)); 16 | sum[rt<<1|1] = stt[rt] * (m >> 1); 17 | stt[rt] = 0; 18 | } 19 | } 20 | void build(int l,int r,int rt=1) 21 | { 22 | stt[rt] = 0; 23 | if (l == r) 24 | { 25 | sum[rt]=1; 26 | return ; 27 | } 28 | int m = (l + r) >> 1; 29 | build(lson); 30 | build(rson); 31 | PushUp(rt); 32 | } 33 | void update(int L,int R,int c,int l,int r,int rt=1) 34 | { 35 | if (L <= l && r <= R) 36 | { 37 | stt[rt] = c; 38 | sum[rt] = c * (r - l + 1); 39 | return ; 40 | } 41 | PushDown(rt, r - l + 1); 42 | int m = (l + r) >> 1; 43 | if (L <= m) update(L, R, c, lson); 44 | if (m < R) update(L, R, c, rson); 45 | PushUp(rt); 46 | } 47 | int query(int L,int R,int l,int r,int rt=1) 48 | { 49 | if (L <= l && r <= R) 50 | { 51 | return sum[rt]; 52 | } 53 | PushDown(rt, r - l + 1); 54 | int m = (l + r) >> 1; 55 | int ret = 0; 56 | if (L <= m) ret += query(L, R, lson); 57 | if (m < R) ret += query(L, R, rson); 58 | return ret; 59 | } 60 | int main() 61 | { 62 | int t; 63 | cin>>t; 64 | int cas=0; 65 | while(t--) 66 | { 67 | int n,q; 68 | cin>>n>>q; 69 | build(1,n); 70 | while(q--) 71 | { 72 | int l,r,c; 73 | scanf("%d%d%d",&l,&r,&c); 74 | update(l,r,c,1,n); 75 | } 76 | printf("Case %d: The total value of the hook is %d.\n",++cas,sum[1]); 77 | } 78 | return 0; 79 | } 80 | -------------------------------------------------------------------------------- /模板/4_数据结构/5_线段树/6_线段树相关例题/区间更新/2_POJ3468.cpp: -------------------------------------------------------------------------------- 1 | #define lson l,m,rt<<1 2 | #define rson m+1,r,rt<<1|1 3 | const int NV = 100005; 4 | long long add[NV<<2],sum[NV<<2]; 5 | void PushUp(int rt) 6 | { 7 | sum[rt]=sum[rt<<1]+sum[rt<<1|1]; 8 | } 9 | void PushDown(int rt,int m) 10 | { 11 | if (add[rt]) 12 | { 13 | add[rt<<1] += add[rt]; 14 | add[rt<<1|1] += add[rt]; 15 | sum[rt<<1] += add[rt] * (m - (m >> 1)); 16 | sum[rt<<1|1] += add[rt] * (m >> 1); 17 | add[rt] = 0; 18 | } 19 | } 20 | void build(int l,int r,int rt=1) 21 | { 22 | add[rt] = 0; 23 | if (l == r) 24 | { 25 | scanf("%lld",&sum[rt]); 26 | return ; 27 | } 28 | int m = (l + r) >> 1; 29 | build(lson); 30 | build(rson); 31 | PushUp(rt); 32 | } 33 | void update(int L,int R,long long c,int l,int r,int rt=1) 34 | { 35 | if (L <= l && r <= R) 36 | { 37 | add[rt] += c; 38 | sum[rt] += c * (r - l + 1); 39 | return ; 40 | } 41 | PushDown(rt, r - l + 1); 42 | int m = (l + r) >> 1; 43 | if (L <= m) update(L, R, c, lson); 44 | if (m < R) update(L, R, c, rson); 45 | PushUp(rt); 46 | } 47 | long long query(int L,int R,int l,int r,int rt=1) 48 | { 49 | if (L <= l && r <= R) 50 | { 51 | return sum[rt]; 52 | } 53 | PushDown(rt, r - l + 1); 54 | int m = (l + r) >> 1; 55 | long long ret = 0; 56 | if (L <= m) ret += query(L, R, lson); 57 | if (m < R) ret += query(L, R, rson); 58 | return ret; 59 | } 60 | int main() 61 | { 62 | int n,q; 63 | cin>>n>>q; 64 | build(1,n); 65 | while(q--) 66 | { 67 | char s[5]; 68 | int l,r; 69 | scanf("%s%d%d",s,&l,&r); 70 | if (s[0]=='Q') 71 | printf("%lld\n",query(l,r,1,n)); 72 | else 73 | { 74 | long long c; 75 | scanf("%lld",&c); 76 | update(l,r,c,1,n); 77 | } 78 | } 79 | return 0; 80 | } 81 | -------------------------------------------------------------------------------- /模板/4_数据结构/5_线段树/6_线段树相关例题/区间更新/3_POJ2528.cpp: -------------------------------------------------------------------------------- 1 | #define lson l,m,rt<<1 2 | #define rson m+1,r,rt<<1|1 3 | const int NV = 20005; 4 | int col[NV<<2]; 5 | void PushDown(int rt,int m) 6 | { 7 | if (col[rt]) 8 | { 9 | col[rt<<1] = col[rt]; 10 | col[rt<<1|1] = col[rt]; 11 | col[rt] = 0; 12 | } 13 | } 14 | void build(int l,int r,int rt=1) 15 | { 16 | col[rt] = 0; 17 | if (l == r) 18 | { 19 | return ; 20 | } 21 | int m = (l + r) >> 1; 22 | build(lson); 23 | build(rson); 24 | } 25 | void update(int L,int R,int c,int l,int r,int rt=1) 26 | { 27 | if (L <= l && r <= R) 28 | { 29 | col[rt] = c; 30 | return ; 31 | } 32 | PushDown(rt, r - l + 1); 33 | int m = (l + r) >> 1; 34 | if (L <= m) update(L, R, c, lson); 35 | if (m < R) update(L, R, c, rson); 36 | } 37 | int query(int L,int l,int r,int rt=1) 38 | { 39 | if (L == l && l == r) 40 | { 41 | return col[rt]; 42 | } 43 | PushDown(rt, r - l + 1); 44 | int m = (l + r) >> 1; 45 | if (L <= m) return query(L, lson); 46 | else return query(L, rson); 47 | } 48 | int discrete(int data[],int n,int dis[]) 49 | { 50 | int sub[n+1]; 51 | memcpy(sub,data,sizeof(sub)); 52 | sort(sub+1,sub+n+1); 53 | int m=unique(sub+1,sub+n+1)-sub-1; 54 | for(int i=1; i<=n; i++) 55 | dis[i]=lower_bound(sub+1,sub+m+1,data[i])-sub; 56 | return m; 57 | } 58 | int a[NV],dis[NV],co[NV]; 59 | int main() 60 | { 61 | int t; 62 | cin>>t; 63 | while(t--) 64 | { 65 | int n; 66 | scanf("%d",&n); 67 | for (int i=1; i<=n; i++) 68 | scanf("%d%d",&a[i],&a[i+n]); 69 | discrete(a,2*n,dis); 70 | build(1,2*n); 71 | for (int i=1; i<=n; i++) 72 | update(dis[i],dis[i+n],i,1,2*n); 73 | memset(co,0,sizeof(co)); 74 | for (int i=1; i<=2*n; i++) 75 | co[query(i,1,2*n)]=1; 76 | printf("%d\n",accumulate(co+1,co+2*n+1,0)); 77 | } 78 | return 0; 79 | } 80 | -------------------------------------------------------------------------------- /模板/4_数据结构/5_线段树/6_线段树相关例题/区间更新/4_POJ1436.cpp: -------------------------------------------------------------------------------- 1 | #define lson l,m,rt<<1 2 | #define rson m+1,r,rt<<1|1 3 | const int NV = 8005; 4 | int stt[NV<<3]; 5 | bool a[NV][NV]; 6 | void PushDown(int rt,int m) 7 | { 8 | if (stt[rt]) 9 | { 10 | stt[rt<<1] = stt[rt]; 11 | stt[rt<<1|1] = stt[rt]; 12 | stt[rt] = 0; 13 | } 14 | } 15 | void build(int l,int r,int rt=1) 16 | { 17 | stt[rt] = 0; 18 | if (l == r) 19 | { 20 | return ; 21 | } 22 | int m = (l + r) >> 1; 23 | build(lson); 24 | build(rson); 25 | } 26 | void update(int L,int R,int c,int l,int r,int rt=1) 27 | { 28 | if (L <= l && r <= R) 29 | { 30 | stt[rt] = c; 31 | return ; 32 | } 33 | PushDown(rt, r - l + 1); 34 | int m = (l + r) >> 1; 35 | if (L <= m) update(L, R, c, lson); 36 | if (m < R) update(L, R, c, rson); 37 | } 38 | void query(int L,int R,int c,int l,int r,int rt=1) 39 | { 40 | if (stt[rt]) 41 | { 42 | a[stt[rt]][c]=1; 43 | return; 44 | } 45 | if (l == r) 46 | { 47 | return; 48 | } 49 | PushDown(rt, r - l + 1); 50 | int m = (l + r) >> 1; 51 | if (L <= m) query(L, R, c, lson); 52 | if (m < R) query(L, R, c, rson); 53 | } 54 | struct node 55 | { 56 | int x,y1,y2; 57 | } q[NV]; 58 | bool cmp(node a,node b) 59 | { 60 | return a.x>t; 66 | while(t--) 67 | { 68 | int n; 69 | scanf("%d",&n); 70 | for (int i=1; i<=n; i++) 71 | { 72 | scanf("%d%d%d",&q[i].y1,&q[i].y2,&q[i].x); 73 | q[i].y1*=2; 74 | q[i].y1++; 75 | q[i].y2*=2; 76 | q[i].y2++; 77 | } 78 | sort(q+1,q+1+n,cmp); 79 | build(1,16001); 80 | memset(a,0,sizeof(a)); 81 | for (int i=1; i<=n; i++) 82 | { 83 | query(q[i].y1,q[i].y2,i,1,16001); 84 | update(q[i].y1,q[i].y2,i,1,16001); 85 | } 86 | int ans=0; 87 | for (int i=1; i<=n; i++) 88 | for (int j=1; j<=n; j++) 89 | if (a[i][j]) 90 | for (int k=1; k<=n; k++) 91 | ans+=a[i][k]&&a[j][k]; 92 | printf("%d\n",ans); 93 | } 94 | return 0; 95 | } 96 | -------------------------------------------------------------------------------- /模板/4_数据结构/5_线段树/6_线段树相关例题/区间更新/5_POJ2991.cpp: -------------------------------------------------------------------------------- 1 | #define lson l,m,rt<<1 2 | #define rson m+1,r,rt<<1|1 3 | const int NV = 10005; 4 | double add[NV<<2],x[NV<<2],y[NV<<2],ang[NV<<2]; 5 | //ang不需要pushup,因为查询是单点查询 6 | void PushUp(int rt) 7 | { 8 | x[rt]=x[rt<<1]+x[rt<<1|1]; 9 | y[rt]=y[rt<<1]+y[rt<<1|1]; 10 | } 11 | void PushDown(int rt,int m) 12 | { 13 | if (add[rt]) 14 | { 15 | ang[rt<<1] += add[rt]; 16 | ang[rt<<1|1] += add[rt]; 17 | add[rt<<1] += add[rt]; 18 | add[rt<<1|1] += add[rt]; 19 | double xx=x[rt<<1],yy=y[rt<<1]; 20 | x[rt<<1] = cos(add[rt])*xx-sin(add[rt])*yy; 21 | y[rt<<1] = sin(add[rt])*xx+cos(add[rt])*yy; 22 | xx=x[rt<<1|1],yy=y[rt<<1|1]; 23 | x[rt<<1|1] = cos(add[rt])*xx-sin(add[rt])*yy; 24 | y[rt<<1|1] = sin(add[rt])*xx+cos(add[rt])*yy; 25 | add[rt] = 0; 26 | } 27 | } 28 | void build(int l,int r,int rt=1) 29 | { 30 | add[rt] = ang[rt] = 0; 31 | if (l == r) 32 | { 33 | scanf("%lf",&y[rt]); 34 | x[rt] = 0; 35 | // ang[rt] = pi/2; //此处可以不加,因为只需要相对值 36 | return ; 37 | } 38 | int m = (l + r) >> 1; 39 | build(lson); 40 | build(rson); 41 | PushUp(rt); 42 | } 43 | void update(int L,int R,double c,int l,int r,int rt=1) 44 | { 45 | if (L <= l && r <= R) 46 | { 47 | ang[rt] += c; 48 | add[rt] += c; 49 | double xx=x[rt],yy=y[rt]; 50 | x[rt] = cos(c)*xx-sin(c)*yy; 51 | y[rt] = sin(c)*xx+cos(c)*yy; 52 | return ; 53 | } 54 | PushDown(rt, r - l + 1); 55 | int m = (l + r) >> 1; 56 | if (L <= m) update(L, R, c, lson); 57 | if (m < R) update(L, R, c, rson); 58 | PushUp(rt); 59 | } 60 | double query(int L,int l,int r,int rt=1) 61 | { 62 | if (L == l && l == r) 63 | { 64 | return ang[rt]; 65 | } 66 | PushDown(rt, r - l + 1); 67 | int m = (l + r) >> 1; 68 | if (L <= m) return query(L, lson); 69 | else return query(L, rson); 70 | } 71 | int main() 72 | { 73 | int n,q; 74 | while(scanf("%d%d",&n,&q)!=EOF) 75 | { 76 | build(1,n); 77 | while(q--) 78 | { 79 | int s,d; 80 | scanf("%d%d",&s,&d); 81 | update(s+1,n,d/180.0*pi-(query(s+1,1,n)-query(s,1,n)+pi),1,n); 82 | printf("%.2f %.2f\n",x[1],y[1]); 83 | } 84 | puts(""); 85 | } 86 | return 0; 87 | } 88 | -------------------------------------------------------------------------------- /模板/4_数据结构/5_线段树/6_线段树相关例题/区间更新/HDU4973.cpp: -------------------------------------------------------------------------------- 1 | #define lson l,m,rt<<1 2 | #define rson m+1,r,rt<<1|1 3 | const int NV = 50005; 4 | long long mul[NV<<2],sum[NV<<2],mx[NV<<2]; 5 | void PushUp(int rt) 6 | { 7 | sum[rt]=sum[rt<<1]+sum[rt<<1|1]; 8 | mx[rt]=max(mx[rt<<1],mx[rt<<1|1]); 9 | } 10 | void PushDown(int rt,int m) 11 | { 12 | if (mul[rt]!=1) 13 | { 14 | mul[rt<<1] *= mul[rt]; 15 | mul[rt<<1|1] *= mul[rt]; 16 | sum[rt<<1] *= mul[rt]; 17 | sum[rt<<1|1] *= mul[rt]; 18 | mx[rt<<1] *= mul[rt]; 19 | mx[rt<<1|1] *= mul[rt]; 20 | mul[rt] = 1; 21 | } 22 | } 23 | void build(int l,int r,int rt=1) 24 | { 25 | mul[rt] = 1; 26 | if (l == r) 27 | { 28 | sum[rt]=1; 29 | mx[rt]=1; 30 | return ; 31 | } 32 | int m = (l + r) >> 1; 33 | build(lson); 34 | build(rson); 35 | PushUp(rt); 36 | } 37 | void update(int L,long long c,int l,int r,int rt) 38 | { 39 | if (L == l && l == r) 40 | { 41 | sum[rt] += c; 42 | mx[rt] += c; 43 | return ; 44 | } 45 | PushDown(rt, r - l + 1); 46 | int m = (l + r) >> 1; 47 | if (L <= m) update(L, c, lson); 48 | else update(L, c, rson); 49 | PushUp(rt); 50 | } 51 | void update(int L,int R,long long c,int l,int r,int rt) 52 | { 53 | if (L <= l && r <= R) 54 | { 55 | mul[rt] *= c; 56 | sum[rt] *= c; 57 | mx[rt] *= c; 58 | return ; 59 | } 60 | PushDown(rt, r - l + 1); 61 | int m = (l + r) >> 1; 62 | if (L <= m) update(L, R, c, lson); 63 | if (m < R) update(L, R, c, rson); 64 | PushUp(rt); 65 | } 66 | long long num; 67 | int query(long long c,int l,int r,int rt) 68 | { 69 | if (l == r) 70 | { 71 | num=c; 72 | return l; 73 | } 74 | PushDown(rt, r - l + 1); 75 | int m = (l + r) >> 1; 76 | if (sum[rt<<1]>=c) return query(c, lson); 77 | else return query(c-sum[rt<<1], rson); 78 | } 79 | long long query(int L,int R,int l,int r,int rt) 80 | { 81 | if (L <= l && r <= R) 82 | { 83 | return mx[rt]; 84 | } 85 | PushDown(rt, r - l + 1); 86 | int m = (l + r) >> 1; 87 | long long ret = 0; 88 | if (L <= m) ret = max(ret,query(L, R, lson)); 89 | if (m < R) ret = max(ret,query(L, R, rson)); 90 | return ret; 91 | } 92 | int main() 93 | { 94 | int t; 95 | cin>>t; 96 | int cas=0; 97 | while(t--) 98 | { 99 | printf("Case #%d:\n",++cas); 100 | int n,m; 101 | scanf("%d%d",&n,&m); 102 | build(1,n); 103 | while(m--) 104 | { 105 | char str[5]; 106 | long long a,b; 107 | scanf("%s%I64d%I64d",str,&a,&b); 108 | long long mx=0,s1,s2,mx1=0,mx2=0; 109 | int l=query(a,1,n,1); 110 | s1=num; 111 | mx1=query(l,l,1,n,1)-s1+1; 112 | l++; 113 | int r=query(b,1,n,1); 114 | s2=num; 115 | mx2=s2; 116 | r--; 117 | if (str[0]=='Q') 118 | { 119 | if (l<=r) mx=query(l,r,1,n,1); 120 | if (l-1!=r+1) mx=max(mx,max(mx1,mx2)); 121 | else mx=b-a+1; 122 | printf("%I64d\n",mx); 123 | } 124 | else 125 | { 126 | if (l<=r) update(l,r,2,1,n,1); 127 | if (l-1==r+1) 128 | update(l-1,b-a+1,1,n,1); 129 | else 130 | { 131 | if (mx1) update(l-1,mx1,1,n,1); 132 | if (mx2) update(r+1,mx2,1,n,1); 133 | } 134 | } 135 | } 136 | } 137 | return 0; 138 | } 139 | -------------------------------------------------------------------------------- /模板/4_数据结构/5_线段树/6_线段树相关例题/区间更新/ZOJProblemSet-3632.cpp: -------------------------------------------------------------------------------- 1 | #define lson l,m,rt<<1 2 | #define rson m+1,r,rt<<1|1 3 | #define ll long long 4 | const int NV = 55555; 5 | long long stt[NV << 2], mn[NV << 2]; 6 | void PushUp(int rt) 7 | { 8 | mn[rt] = min(mn[rt << 1], mn[rt << 1 | 1]); 9 | } 10 | void PushDown(int rt, int m) 11 | { 12 | if (stt[rt] != inf) 13 | { 14 | stt[rt << 1] = min(stt[rt], stt[rt << 1]); 15 | stt[rt << 1 | 1] = min(stt[rt], stt[rt << 1 | 1]); 16 | mn[rt << 1] = min(mn[rt << 1], stt[rt << 1]); 17 | mn[rt << 1 | 1] = min(mn[rt << 1 | 1], stt[rt << 1 | 1]); 18 | stt[rt] = inf; 19 | } 20 | } 21 | void build(int l, int r, int rt = 1) 22 | { 23 | stt[rt] = inf; 24 | if (l == r) 25 | { 26 | mn[rt] = inf; 27 | return ; 28 | } 29 | int m = (l + r) >> 1; 30 | build(lson); 31 | build(rson); 32 | PushUp(rt); 33 | } 34 | void update(int L, int R, long long c, int l, int r, int rt = 1) 35 | { 36 | if (L <= l && r <= R) 37 | { 38 | stt[rt] = min(c, stt[rt]); 39 | mn[rt] = min(mn[rt], stt[rt]); 40 | return ; 41 | } 42 | PushDown(rt, r - l + 1); 43 | int m = (l + r) >> 1; 44 | if (L <= m) update(L, R, c, lson); 45 | if (m < R) update(L, R, c, rson); 46 | PushUp(rt); 47 | } 48 | ll query(int L, int l, int r, int rt = 1) 49 | { 50 | if (L == l && l == r) 51 | { 52 | return mn[rt]; 53 | } 54 | PushDown(rt, r - l + 1); 55 | int m = (l + r) >> 1; 56 | if (L <= m) return query(L, lson); 57 | else return query(L, rson); 58 | } 59 | ll mon[NV]; 60 | int day[NV], n; 61 | int main() 62 | { 63 | while(~scanf("%d", &n)) 64 | { 65 | for (int i = 1; i <= n; i++) scanf("%lld", mon + i); 66 | for (int i = 1; i <= n; i++) scanf("%d", day + i); 67 | build(1, n, 1); 68 | ll get = 0; 69 | for (int i = 1; i <= n; i++) 70 | { 71 | update(i, min(i + day[i] - 1, n), get + mon[i], 1, n, 1); 72 | get = query(i, 1, n, 1); 73 | //cout<> 1; 17 | build(lson); 18 | build(rson); 19 | PushUp(rt); 20 | } 21 | void update(int L,int c,int l,int r,int rt=1) 22 | { 23 | if (L == l && l == r) 24 | { 25 | sum[rt] += c; 26 | return ; 27 | } 28 | int m = (l + r) >> 1; 29 | if (L <= m) update(L, c, lson); 30 | else update(L, c, rson); 31 | PushUp(rt); 32 | } 33 | int query(int L,int R,int l,int r,int rt=1) 34 | { 35 | if (L <= l && r <= R) 36 | return sum[rt]; 37 | int m = (l + r) >> 1; 38 | int ret = 0; 39 | if (L <= m) ret += query(L, R, lson); 40 | if (m < R) ret += query(L, R, rson); 41 | return ret; 42 | } 43 | int main() 44 | { 45 | int t,cas=0; 46 | cin>>t; 47 | while(t--) 48 | { 49 | int n; 50 | scanf("%d",&n); 51 | int x,v; 52 | build(1,n); 53 | for (int i=1; i<=n; i++) 54 | { 55 | scanf("%d",&v); 56 | update(i,v,1,n); 57 | } 58 | printf("Case %d:\n",++cas); 59 | char s[10]; 60 | while(scanf("%s",s),s[0]!='E') 61 | { 62 | scanf("%d%d",&x,&v); 63 | if (s[0]=='A') 64 | update(x,v,1,n); 65 | if (s[0]=='S') 66 | update(x,-v,1,n); 67 | if (s[0]=='Q') 68 | printf("%d\n",query(x,v,1,n)); 69 | } 70 | } 71 | return 0; 72 | } 73 | -------------------------------------------------------------------------------- /模板/4_数据结构/5_线段树/6_线段树相关例题/单点更新/2_HDU1754.cpp: -------------------------------------------------------------------------------- 1 | #define lson l,m,rt<<1 2 | #define rson m+1,r,rt<<1|1 3 | const int NV = 200005; 4 | int mx[NV<<2]; 5 | void PushUp(int rt) 6 | { 7 | mx[rt]=max(mx[rt<<1],mx[rt<<1|1]); 8 | } 9 | void build(int l,int r,int rt=1) 10 | { 11 | if (l == r) 12 | { 13 | scanf("%d",&mx[rt]); 14 | return ; 15 | } 16 | int m = (l + r) >> 1; 17 | build(lson); 18 | build(rson); 19 | PushUp(rt); 20 | } 21 | void update(int L,int c,int l,int r,int rt=1) 22 | { 23 | if (L == l && l == r) 24 | { 25 | mx[rt] = c; 26 | return ; 27 | } 28 | int m = (l + r) >> 1; 29 | if (L <= m) update(L, c, lson); 30 | else update(L, c, rson); 31 | PushUp(rt); 32 | } 33 | int query(int L,int R,int l,int r,int rt=1) 34 | { 35 | if (L <= l && r <= R) 36 | return mx[rt]; 37 | int m = (l + r) >> 1; 38 | int ret = -1; 39 | if (L <= m) ret = max(ret,query(L, R, lson)); 40 | if (m < R) ret = max(ret,query(L, R, rson)); 41 | return ret; 42 | } 43 | int main() 44 | { 45 | int n,m; 46 | while(scanf("%d%d",&n,&m)!=EOF) 47 | { 48 | build(1,n); 49 | char s[10]; 50 | int a,b; 51 | while(m--) 52 | { 53 | scanf("%s%d%d",s,&a,&b); 54 | if (s[0]=='U') 55 | update(a,b,1,n); 56 | else 57 | printf("%d\n",query(a,b,1,n)); 58 | } 59 | } 60 | return 0; 61 | } 62 | -------------------------------------------------------------------------------- /模板/4_数据结构/5_线段树/6_线段树相关例题/单点更新/3_HDU1394.cpp: -------------------------------------------------------------------------------- 1 | #define lson l,m,rt<<1 2 | #define rson m+1,r,rt<<1|1 3 | const int NV = 100005; 4 | int sum[NV<<2]; 5 | void PushUp(int rt) 6 | { 7 | sum[rt]=sum[rt<<1]+sum[rt<<1|1]; 8 | } 9 | void build(int l,int r,int rt=1) 10 | { 11 | if (l == r) 12 | { 13 | sum[rt]=0; 14 | return ; 15 | } 16 | int m = (l + r) >> 1; 17 | build(lson); 18 | build(rson); 19 | PushUp(rt); 20 | } 21 | void update(int L,int c,int l,int r,int rt=1) 22 | { 23 | if (L == l && l == r) 24 | { 25 | sum[rt] += c; 26 | return ; 27 | } 28 | int m = (l + r) >> 1; 29 | if (L <= m) update(L, c, lson); 30 | else update(L, c, rson); 31 | PushUp(rt); 32 | } 33 | int query(int L,int R,int l,int r,int rt=1) 34 | { 35 | if (L <= l && r <= R) 36 | return sum[rt]; 37 | int m = (l + r) >> 1; 38 | int ret = 0; 39 | if (L <= m) ret += query(L, R, lson); 40 | if (m < R) ret += query(L, R, rson); 41 | return ret; 42 | } 43 | int a[5005]; 44 | int main() 45 | { 46 | int n; 47 | while(~scanf("%d",&n)) 48 | { 49 | int ans=0; 50 | build(1,n); 51 | for (int i=1; i<=n; i++) 52 | { 53 | scanf("%d",&a[i]); 54 | ans+=query(a[i]+2,n,1,n); 55 | update(a[i]+1,1,1,n); 56 | } 57 | int mn=ans; 58 | for (int i=1; i<=n; i++) 59 | { 60 | ans+=n-2*a[i]-1; 61 | mn=min(mn,ans); 62 | } 63 | printf("%d\n",mn); 64 | } 65 | return 0; 66 | } 67 | -------------------------------------------------------------------------------- /模板/4_数据结构/5_线段树/6_线段树相关例题/单点更新/4_HDU2795.cpp: -------------------------------------------------------------------------------- 1 | #define lson l,m,rt<<1 2 | #define rson m+1,r,rt<<1|1 3 | int h,w,n; 4 | const int NV = 200005; 5 | int mx[NV<<2]; 6 | void PushUp(int rt) 7 | { 8 | mx[rt]=max(mx[rt<<1],mx[rt<<1|1]); 9 | } 10 | void build(int l,int r,int rt=1) 11 | { 12 | if (l == r) 13 | { 14 | mx[rt]=w; 15 | return ; 16 | } 17 | int m = (l + r) >> 1; 18 | build(lson); 19 | build(rson); 20 | PushUp(rt); 21 | } 22 | void update(int c,int l,int r,int rt=1) 23 | { 24 | if (l == r) 25 | { 26 | mx[rt]-=c; 27 | printf("%d\n",l); 28 | return; 29 | } 30 | int m = (l + r) >> 1; 31 | if (mx[rt<<1]>=c) update(c, lson); 32 | else update(c, rson); 33 | PushUp(rt); 34 | } 35 | int main() 36 | { 37 | while(~scanf("%d%d%d",&h,&w,&n)) 38 | { 39 | build(1,min(h,200000)); 40 | for (int i=1; i<=n; i++) 41 | { 42 | int x; 43 | scanf("%d",&x); 44 | if (x<=mx[1]) update(x,1,min(h,200000)); 45 | else puts("-1"); 46 | } 47 | } 48 | return 0; 49 | } 50 | -------------------------------------------------------------------------------- /模板/4_数据结构/5_线段树/6_线段树相关例题/单点更新/5_POJ2828.cpp: -------------------------------------------------------------------------------- 1 | #define lson l,m,rt<<1 2 | #define rson m+1,r,rt<<1|1 3 | const int NV = 200005; 4 | int sum[NV<<2]; 5 | void PushUp(int rt) 6 | { 7 | sum[rt]=sum[rt<<1]+sum[rt<<1|1]; 8 | } 9 | void build(int l,int r,int rt=1) 10 | { 11 | if (l == r) 12 | { 13 | sum[rt]=1; 14 | return ; 15 | } 16 | int m = (l + r) >> 1; 17 | build(lson); 18 | build(rson); 19 | PushUp(rt); 20 | } 21 | int update(int c,int l,int r,int rt=1) 22 | { 23 | if (l == r) 24 | { 25 | sum[rt]--; 26 | return l; 27 | } 28 | int m = (l + r) >> 1; 29 | int ret; 30 | if (sum[rt<<1]>=c) ret=update(c, lson); 31 | else ret=update(c-sum[rt<<1], rson); 32 | PushUp(rt); 33 | return ret; 34 | } 35 | int a[200005]; 36 | int q[200005]; 37 | int w[200005]; 38 | int main() 39 | { 40 | int n; 41 | while(scanf("%d",&n)!=EOF) 42 | { 43 | build(1,n); 44 | for (int i=1; i<=n; i++) 45 | scanf("%d%d",&q[i],&w[i]); 46 | for (int i=n; i>=1; i--) 47 | a[update(q[i]+1,1,n)]=w[i]; 48 | for (int i=1; i<=n; i++) 49 | printf("%d%c",a[i]," \n"[i==n]); 50 | } 51 | return 0; 52 | } 53 | -------------------------------------------------------------------------------- /模板/4_数据结构/5_线段树/6_线段树相关例题/单点更新/6_POJ2886.cpp: -------------------------------------------------------------------------------- 1 | #define lson l,m,rt<<1 2 | #define rson m+1,r,rt<<1|1 3 | const int NV = 500005; 4 | int sum[NV<<2]; 5 | void PushUp(int rt) 6 | { 7 | sum[rt]=sum[rt<<1]+sum[rt<<1|1]; 8 | } 9 | void build(int l,int r,int rt=1) 10 | { 11 | if (l == r) 12 | { 13 | sum[rt]=1; 14 | return ; 15 | } 16 | int m = (l + r) >> 1; 17 | build(lson); 18 | build(rson); 19 | PushUp(rt); 20 | } 21 | int update(int c,int l,int r,int rt=1) 22 | { 23 | if (l == r) 24 | { 25 | sum[rt]--; 26 | return l; 27 | } 28 | int m = (l + r) >> 1; 29 | int ret; 30 | if (sum[rt<<1]>=c) ret=update(c, lson); 31 | else ret=update(c-sum[rt<<1], rson); 32 | PushUp(rt); 33 | return ret; 34 | } 35 | int y[500005]= {}; 36 | void getfactor(int n) 37 | { 38 | int x=sqrt(n); 39 | for (int i=1; i<=x; i++) 40 | { 41 | for (int j=i+1; j*i<=n; j++) 42 | y[i*j]+=2; 43 | y[i*i]++; 44 | } 45 | } 46 | char s[500005][20]; 47 | int x[500005]; 48 | int main() 49 | { 50 | getfactor(500000); 51 | int n,k; 52 | while(~scanf("%d%d",&n,&k)) 53 | { 54 | build(1,n); 55 | for (int i=1; i<=n; i++) 56 | scanf("%s%d",s[i],&x[i]); 57 | int m,mx=-1; 58 | for (int i=1; i<=n; i++) 59 | if (y[i]>mx) 60 | { 61 | m=i; 62 | mx=y[i]; 63 | } 64 | int ans=k; 65 | while(m--) 66 | { 67 | ans=update(k,1,n); 68 | if (!m) continue; 69 | if (x[ans]>0) 70 | k=((k-1+x[ans]-1)%sum[1]+sum[1])%sum[1]+1; 71 | else 72 | k=((k-1+x[ans])%sum[1]+sum[1])%sum[1]+1; 73 | } 74 | printf("%s %d\n",s[ans],mx); 75 | } 76 | return 0; 77 | } 78 | -------------------------------------------------------------------------------- /模板/4_数据结构/5_线段树/6_线段树相关例题/单点更新/7_HDU4288.cpp: -------------------------------------------------------------------------------- 1 | #define lson l,m,rt<<1 2 | #define rson m+1,r,rt<<1|1 3 | const int NV = 100005; 4 | int sum[NV<<2]; 5 | long long ans[NV<<2][5]; 6 | void PushUp(int rt) 7 | { 8 | sum[rt]=sum[rt<<1]+sum[rt<<1|1]; 9 | for (int i=0; i<5; i++) 10 | ans[rt][i]=ans[rt<<1][i]+ans[rt<<1|1][((i-sum[rt<<1])%5+5)%5]; 11 | } 12 | void build(int l,int r,int rt=1) 13 | { 14 | if (l == r) 15 | { 16 | sum[rt]=0; 17 | memset(ans[rt],0,sizeof(ans[rt])); 18 | return ; 19 | } 20 | int m = (l + r) >> 1; 21 | build(lson); 22 | build(rson); 23 | PushUp(rt); 24 | } 25 | void update(int L,int t,int c,int l,int r,int rt=1) 26 | { 27 | if (L == l && l == r) 28 | { 29 | sum[rt]+=t; 30 | ans[rt][1]+=t*c; 31 | return ; 32 | } 33 | int m = (l + r) >> 1; 34 | if (L <= m) update(L, t, c, lson); 35 | else update(L, t, c, rson); 36 | PushUp(rt); 37 | } 38 | int discrete(int data[],int n,int dis[]) 39 | { 40 | int sub[n+1]; 41 | memcpy(sub,data,sizeof(sub)); 42 | sort(sub+1,sub+n+1); 43 | int m=unique(sub+1,sub+n+1)-sub-1; 44 | for(int i=1; i<=n; i++) 45 | dis[i]=lower_bound(sub+1,sub+m+1,data[i])-sub; 46 | return m; 47 | } 48 | int op[100005],data[100005],dis[100005]; 49 | int main() 50 | { 51 | int n; 52 | while(~scanf("%d",&n)) 53 | { 54 | char s[5]; 55 | int m=0; 56 | for (int i=1; i<=n; i++) 57 | { 58 | scanf("%s",s); 59 | if (s[0]=='a') op[i]=1,scanf("%d",&data[++m]); 60 | else if (s[0]=='d') op[i]=2,scanf("%d",&data[++m]); 61 | else op[i]=3; 62 | } 63 | m=discrete(data,m,dis); 64 | build(1,m); 65 | int x=0; 66 | for (int i=1; i<=n; i++) 67 | { 68 | if (op[i]==1) x++,update(dis[x],1,data[x],1,m); 69 | else if (op[i]==2) x++,update(dis[x],-1,data[x],1,m); 70 | else printf("%I64d\n",ans[1][3]); 71 | } 72 | } 73 | return 0; 74 | } 75 | -------------------------------------------------------------------------------- /模板/4_数据结构/5_线段树/6_线段树相关例题/单点更新/8_CF19D.cpp: -------------------------------------------------------------------------------- 1 | #define lson l,m,rt<<1 2 | #define rson m+1,r,rt<<1|1 3 | const int NV = 200005; 4 | set stt[NV]; 5 | int mx[NV<<2]; 6 | void PushUp(int rt) 7 | { 8 | mx[rt]=max(mx[rt<<1],mx[rt<<1|1]); 9 | } 10 | void build(int l,int r,int rt=1) 11 | { 12 | if (l == r) 13 | { 14 | mx[rt]=-1; 15 | return ; 16 | } 17 | int m = (l + r) >> 1; 18 | build(lson); 19 | build(rson); 20 | PushUp(rt); 21 | } 22 | void add(int L,int c,int l,int r,int rt=1) 23 | { 24 | if (l == r) 25 | { 26 | mx[rt] = max(mx[rt],c); 27 | stt[l].insert(c); 28 | return ; 29 | } 30 | int m = (l + r) >> 1; 31 | if (L <= m) add(L, c, lson); 32 | else add(L, c, rson); 33 | PushUp(rt); 34 | } 35 | void remove(int L,int c,int l,int r,int rt=1) 36 | { 37 | if (l == r) 38 | { 39 | stt[l].erase(c); 40 | mx[rt]=stt[l].empty()?-1:*--stt[l].end(); 41 | return ; 42 | } 43 | int m = (l + r) >> 1; 44 | if (L <= m) remove(L, c, lson); 45 | else remove(L, c, rson); 46 | PushUp(rt); 47 | } 48 | pair find(int L,int c,int l,int r,int rt=1) 49 | { 50 | if (mx[rt]> 1; 53 | pair p=find(L, c, lson); 54 | if (p.second!=-1) return p; 55 | else return find(L, c, rson); 56 | } 57 | int discrete(int data[],int n,int dis[],int index[]) 58 | { 59 | int sub[n+1]; 60 | memcpy(sub,data,sizeof(sub)); 61 | sort(sub+1,sub+n+1); 62 | int m=unique(sub+1,sub+n+1)-sub-1; 63 | for(int i=1; i<=n; i++) 64 | { 65 | dis[i]=lower_bound(sub+1,sub+m+1,data[i])-sub; 66 | index[dis[i]]=data[i]; 67 | } 68 | return m; 69 | } 70 | int dis[NV],op[NV],x[NV],y[NV],index[NV]; 71 | int main() 72 | { 73 | int n; 74 | cin>>n; 75 | for (int i=1; i<=n; i++) 76 | { 77 | char s[10]; 78 | scanf("%s%d%d",s,&x[i],&y[i]); 79 | if (s[0]=='a') op[i]=1; 80 | else if (s[0]=='r') op[i]=2; 81 | else op[i]=3; 82 | } 83 | int m=discrete(x,n,dis,index); 84 | build(1,m); 85 | for (int i=1; i<=n; i++) 86 | { 87 | if (op[i]==1) 88 | add(dis[i],y[i],1,m); 89 | else if (op[i]==2) 90 | remove(dis[i],y[i],1,m); 91 | else 92 | { 93 | pair p=find(dis[i]+1,y[i]+1,1,m); 94 | if (p.second==-1) puts("-1"); 95 | else printf("%d %d\n",index[p.first],p.second); 96 | } 97 | } 98 | return 0; 99 | } 100 | -------------------------------------------------------------------------------- /模板/4_数据结构/5_线段树/6_线段树相关例题/单点更新/9_POJ2481.cpp: -------------------------------------------------------------------------------- 1 | #define lson l,m,rt<<1 2 | #define rson m+1,r,rt<<1|1 3 | const int NV = 100005; 4 | int sum[NV<<2]; 5 | void PushUp(int rt) 6 | { 7 | sum[rt]=sum[rt<<1]+sum[rt<<1|1]; 8 | } 9 | void build(int l,int r,int rt=1) 10 | { 11 | if (l == r) 12 | { 13 | sum[rt]=0; 14 | return ; 15 | } 16 | int m = (l + r) >> 1; 17 | build(lson); 18 | build(rson); 19 | PushUp(rt); 20 | } 21 | void update(int L,int c,int l,int r,int rt=1) 22 | { 23 | if (l == r) 24 | { 25 | sum[rt] += c; 26 | return ; 27 | } 28 | int m = (l + r) >> 1; 29 | if (L <= m) update(L, c, lson); 30 | else update(L, c, rson); 31 | PushUp(rt); 32 | } 33 | int query(int L,int R,int l,int r,int rt=1) 34 | { 35 | if (L <= l && r <= R) 36 | return sum[rt]; 37 | int m = (l + r) >> 1; 38 | int ret = 0; 39 | if (L <= m) ret += query(L, R, lson); 40 | if (m < R) ret += query(L, R, rson); 41 | return ret; 42 | } 43 | struct node 44 | { 45 | int l,r,i; 46 | bool operator<(const node &b) const 47 | { 48 | if (l==b.l) return r>b.r; 49 | return l>n,n) 57 | { 58 | build(1,100001); 59 | for (int i=1; i<=n; i++) 60 | scanf("%d%d",&a[i].l,&a[i].r),a[i].l++,a[i].r++,a[i].i=i; 61 | sort(a+1,a+n+1); 62 | for (int i=1; i<=n; i++) 63 | { 64 | if (a[i].l==a[i-1].l&&a[i].r==a[i-1].r) 65 | ans[a[i].i]=ans[a[i-1].i]; 66 | else 67 | ans[a[i].i]=query(a[i].r,100001,1,100001); 68 | update(a[i].r,1,1,100001); 69 | } 70 | for (int i=1; i<=n; i++) 71 | printf("%d%c",ans[i]," \n"[i==n]); 72 | } 73 | return 0; 74 | } 75 | -------------------------------------------------------------------------------- /模板/4_数据结构/5_线段树/6_线段树相关例题/单点更新/ZOJProblemSet-3612.cpp: -------------------------------------------------------------------------------- 1 | #define lson l,m,rt<<1 2 | #define rson m+1,r,rt<<1|1 3 | const int NV = 50005; 4 | int sum[NV<<2]; 5 | void PushUp(int rt) 6 | { 7 | sum[rt]=sum[rt<<1]+sum[rt<<1|1]; 8 | } 9 | void build(int l,int r,int rt=1) 10 | { 11 | if (l == r) 12 | { 13 | sum[rt]=0; 14 | return ; 15 | } 16 | int m = (l + r) >> 1; 17 | build(lson); 18 | build(rson); 19 | PushUp(rt); 20 | } 21 | int update(int L,int c,int l,int r,int rt=1) 22 | { 23 | if (L == l && l == r) 24 | { 25 | if (c==-1&&sum[rt]==0) return 0; 26 | sum[rt] += c; 27 | return 1; 28 | } 29 | int m = (l + r) >> 1; 30 | int ret; 31 | if (L <= m) ret=update(L, c, lson); 32 | else ret=update(L, c, rson); 33 | PushUp(rt); 34 | return ret; 35 | } 36 | int query(int c,int l,int r,int rt=1) 37 | { 38 | if (l == r) 39 | { 40 | return l; 41 | } 42 | int m = (l + r) >> 1; 43 | int ret; 44 | if (sum[rt<<1]>=c) ret=query(c, lson); 45 | else ret=query(c-sum[rt<<1], rson); 46 | PushUp(rt); 47 | return ret; 48 | } 49 | int discrete(int data[],int n,int dis[],int ind[]) 50 | { 51 | int sub[n+1]; 52 | memcpy(sub,data,sizeof(sub)); 53 | sort(sub+1,sub+n+1); 54 | int m=unique(sub+1,sub+n+1)-sub-1; 55 | for(int i=1; i<=n; i++) 56 | { 57 | dis[i]=lower_bound(sub+1,sub+m+1,data[i])-sub; 58 | ind[dis[i]]=data[i]; 59 | } 60 | return m; 61 | } 62 | int op[NV],data[NV],dis[NV],ind[NV]; 63 | int main() 64 | { 65 | int t; 66 | cin>>t; 67 | while(t--) 68 | { 69 | int n; 70 | scanf("%d",&n); 71 | char s[10]; 72 | for (int i=1; i<=n; i++) 73 | { 74 | scanf("%s",s); 75 | if (s[0]=='a') op[i]=1; 76 | else op[i]=2; 77 | scanf("%d",&data[i]); 78 | } 79 | int m=discrete(data,n,dis,ind); 80 | build(1,m); 81 | for (int i=1; i<=n; i++) 82 | { 83 | if (op[i]==1) 84 | update(dis[i],1,1,m); 85 | else 86 | { 87 | if (!update(dis[i],-1,1,m)) 88 | { 89 | puts("Wrong!"); 90 | continue; 91 | } 92 | } 93 | if (sum[1]==0) puts("Empty!"); 94 | else 95 | { 96 | if (sum[1]%2) printf("%d\n",ind[query(sum[1]/2+1,1,m)]); 97 | else 98 | { 99 | long long l=ind[query(sum[1]/2,1,m)]; 100 | long long r=ind[query(sum[1]/2+1,1,m)]; 101 | if ((l+r)%2) printf("%.1f\n",(l+r)/2.0); 102 | else printf("%lld\n",(l+r)/2); 103 | } 104 | } 105 | } 106 | } 107 | return 0; 108 | } 109 | -------------------------------------------------------------------------------- /模板/4_数据结构/5_线段树/7_动态新建结点的线段树.cpp: -------------------------------------------------------------------------------- 1 | ///这题是区间与1异或,区间求和 2 | #define lson l,m,DL[rt] 3 | #define rson m+1,r,DR[rt] 4 | const int NV = 100005*32*4; 5 | struct seg 6 | { 7 | int sum[NV],add[NV],DL[NV],DR[NV]; 8 | int cnt; 9 | seg() 10 | { 11 | cnt=1; 12 | sum[1]=add[1]=0; 13 | DL[1]=DR[1]=-1; 14 | } 15 | int newnode(int l,int r) 16 | { 17 | cnt++; 18 | sum[cnt]=add[cnt]=0; 19 | DL[cnt]=DR[cnt]=-1; 20 | return cnt; 21 | } 22 | void PushUp(int rt) 23 | { 24 | sum[rt]=sum[DL[rt]]+sum[DR[rt]]; 25 | } 26 | void PushDown(int rt,int m) 27 | { 28 | if (add[rt]) 29 | { 30 | add[DL[rt]] ^= add[rt]; 31 | add[DR[rt]] ^= add[rt]; 32 | sum[DL[rt]] = (m - (m >> 1))-sum[DL[rt]]; 33 | sum[DR[rt]] = (m >> 1)-sum[DR[rt]]; 34 | add[rt] = 0; 35 | } 36 | } 37 | void update(int L,int R,int c,int l,int r,int rt=1) 38 | { 39 | if (L <= l && r <= R) 40 | { 41 | add[rt]^=1; 42 | sum[rt] = (r - l + 1)-sum[rt]; 43 | return ; 44 | } 45 | int m = ((long long)l + r) >> 1; ///long long is important here!!! 46 | if (DL[rt]==-1) DL[rt]=newnode(l,m); 47 | if (DR[rt]==-1) DR[rt]=newnode(m+1,r); 48 | PushDown(rt, r - l + 1); 49 | if (L <= m) update(L, R, c, lson); 50 | if (m < R) update(L, R, c, rson); 51 | PushUp(rt); 52 | } 53 | int query(int L,int R,int l,int r,int rt=1) 54 | { 55 | if (L <= l && r <= R) 56 | { 57 | return sum[rt]; 58 | } 59 | int m = ((long long)l + r) >> 1; ///long long is important here!!! 60 | if (DL[rt]==-1) DL[rt]=newnode(l,m); 61 | if (DR[rt]==-1) DR[rt]=newnode(m+1,r); 62 | PushDown(rt, r - l + 1); 63 | int ret = 0; 64 | if (L <= m) ret += query(L, R, lson); 65 | if (m < R) ret += query(L, R, rson); 66 | return ret; 67 | } 68 | } s; 69 | -------------------------------------------------------------------------------- /模板/4_数据结构/6_左偏树.cpp: -------------------------------------------------------------------------------- 1 | struct node 2 | { 3 | int l,r,dis,val,dad; 4 | } heap[100005]; 5 | int finds(int x) 6 | { 7 | return heap[x].dad == x ? x : heap[x].dad = finds (heap[x].dad); 8 | } 9 | int merge(int x, int y) 10 | { 11 | if (!x) return y; 12 | if (!y) return x; 13 | if (heap[y].val > heap[x].val) swap (x, y); 14 | heap[x].r = merge (heap[x].r, y); 15 | heap[heap[x].r].dad = x; 16 | if (heap[heap[x].l].dis < heap[heap[x].r].dis) 17 | swap (heap[x].l, heap[x].r); 18 | if (heap[x].r == 0) heap[x].dis = 0; 19 | else heap[x].dis = heap[heap[x].r].dis + 1; 20 | return x; 21 | } 22 | int pop(int x) 23 | { 24 | int l = heap[x].l; 25 | int r = heap[x].r; 26 | heap[l].dad = l; 27 | heap[r].dad = r; 28 | heap[x].l = heap[x].r = heap[x].dis = 0; 29 | return merge(l, r); 30 | } 31 | void init(int n) 32 | { 33 | for (int i=1; i<=n; i++) 34 | { 35 | heap[i].l = heap[i].r = heap[i].dis = 0; 36 | heap[i].dad = i; 37 | } 38 | } 39 | int main() 40 | { 41 | int n; 42 | while(cin>>n) 43 | { 44 | init(n); 45 | for (int i=1; i<=n; i++) 46 | scanf("%d",&heap[i].val); 47 | int m; 48 | cin>>m; 49 | while(m--) 50 | { 51 | int x,y; 52 | scanf("%d%d",&x,&y); 53 | x=finds(x); 54 | y=finds(y); 55 | if (x==y) puts("-1"); 56 | else 57 | { 58 | heap[x].val>>=1; 59 | heap[y].val>>=1; 60 | x=merge(pop(x),x);//因为堆顶改变所以要重新pop再merge 61 | y=merge(pop(y),y); 62 | printf("%d\n",heap[merge(x,y)].val); 63 | } 64 | } 65 | } 66 | return 0; 67 | } 68 | 69 | -------------------------------------------------------------------------------- /模板/4_数据结构/6_左偏树.tex: -------------------------------------------------------------------------------- 1 | int finds(int x) 找到x的堆顶\\ 2 | int merge(int x, int y) 将以x和y为堆顶的两个堆合并,返回新堆顶编号\\ 3 | int pop(int x) 删除以x为堆顶的元素(merge与pop都要用finds找到堆顶后才可操作)\\ 4 | void init(int n) 对左偏树初始化\\ -------------------------------------------------------------------------------- /模板/4_数据结构/7_划分树.cpp: -------------------------------------------------------------------------------- 1 | const int NV=100005; 2 | int a[NV],sum[20][NV],s[20][NV]; 3 | void build(int l,int r,int rt=0) 4 | { 5 | int mid=l+r>>1; 6 | int ln=l,rn=mid+1; 7 | int x=a[mid]; 8 | sum[rt][l]=0; 9 | int cnt=mid-l+1; 10 | for (int i=l; i<=r; i++) 11 | if (s[rt][i]l) sum[rt][i]=sum[rt][i-1]; 15 | if (ln<=mid&&(s[rt][i]0)) 16 | s[rt+1][ln++]=s[rt][i],sum[rt][i]++; 17 | else s[rt+1][rn++]=s[rt][i]; 18 | } 19 | if (l>1; 26 | int lsum=0; 27 | if (L>l) lsum=sum[rt][L-1]; 28 | int t=sum[rt][R]-lsum; 29 | if (t>=k) return query(k,l+lsum,l+sum[rt][R]-1,l,mid,rt+1); 30 | else return query(k-t,mid+1+L-l-lsum,mid+1+R-l-sum[rt][R],mid+1,r,rt+1); 31 | } 32 | void init(int n) 33 | { 34 | for (int i=0; i<20; i++) sum[i][0]=0; 35 | for (int i=1; i<=n; i++) s[0][i]=a[i]; 36 | sort(a+1,a+n+1); 37 | build(1,n); 38 | } 39 | -------------------------------------------------------------------------------- /模板/4_数据结构/7_划分树.tex: -------------------------------------------------------------------------------- 1 | 在$n\log n$的时间内离线处理一个序列,在$\log n$的时间查询$[l, r]$区间内的第K大数。 -------------------------------------------------------------------------------- /模板/4_数据结构/9_可持久化线段树.tex: -------------------------------------------------------------------------------- 1 | \subsubsection{可持久化线段树} 2 | \lstinputlisting{"./模板/4_数据结构/9_可持久化线段树/1_可持久化线段树.cpp"} 3 | 4 | \subsubsection{树状数组套可持久化线段树} 5 | 在$\log n$的时间查询$[l, r]$区间内的第K大数,同时支持更新操作。 6 | \lstinputlisting{"./模板/4_数据结构/9_可持久化线段树/2_树状数组套可持久化线段树.cpp"} 7 | \subsubsection{相关例题} 8 | 区间第K大数 9 | \lstinputlisting{"./模板/4_数据结构/9_可持久化线段树/3_POJ2104.cpp"} 10 | 区间更新单点求和,求第K大,二分 \\ 11 | \begin{center} 12 | \includegraphics[scale=1]{./模板/4_数据结构/9_可持久化线段树/4_HDU4866.jpg} 13 | \end{center} 14 | \lstinputlisting{"./模板/4_数据结构/9_可持久化线段树/4_HDU4866.cpp"} -------------------------------------------------------------------------------- /模板/4_数据结构/9_可持久化线段树/1_可持久化线段树.cpp: -------------------------------------------------------------------------------- 1 | #define lson l,m 2 | #define rson m+1,r 3 | const int NV = 100005; 4 | const int NN = NV*25; 5 | int sum[NN],ln[NN],rn[NN]; 6 | int tot,root[NV]; 7 | void PushUp(int k) 8 | { 9 | sum[k]=sum[ln[k]]+sum[rn[k]]; 10 | } 11 | int build(int l,int r) 12 | { 13 | int k=++tot; 14 | if (l == r) 15 | { 16 | sum[k]=0; 17 | return k; 18 | } 19 | int m = (l + r) >> 1; 20 | ln[k]=build(lson); 21 | rn[k]=build(rson); 22 | PushUp(k); 23 | return k; 24 | } 25 | int update(int o,int L,int c,int l,int r) 26 | { 27 | int k=++tot; 28 | sum[k]=sum[o]; 29 | ln[k]=ln[o]; 30 | rn[k]=rn[o]; 31 | if (L == l && l == r) 32 | { 33 | sum[k]+=c; 34 | return k; 35 | } 36 | int m = (l + r) >> 1; 37 | if (L <= m) ln[k]=update(ln[o], L, c, lson); 38 | else rn[k]=update(rn[o], L, c, rson); 39 | PushUp(k); 40 | return k; 41 | } 42 | int query(int a,int b,int L,int l,int r) 43 | { 44 | if (l==r) return l; 45 | int m = (l + r) >> 1; 46 | int tmp=sum[ln[b]]-sum[ln[a]]; 47 | if (L <= tmp) return query(ln[a], ln[b], L, lson); 48 | return query(rn[a], rn[b], L-tmp, rson); 49 | } 50 | int main() 51 | { 52 | root[0]=build(1,n); 53 | for (int i=1; i<=n; i++) 54 | root[i]=update(root[i-1],pos,val,1,n); 55 | query(root[a-1],root[b],pos,1,n); 56 | return 0; 57 | } 58 | -------------------------------------------------------------------------------- /模板/4_数据结构/9_可持久化线段树/2_树状数组套可持久化线段树.cpp: -------------------------------------------------------------------------------- 1 | const int NV=60005; 2 | const int M=NV*40; 3 | int N,m,tot; 4 | int a[NV],T[NV],S[NV],use[NV]; 5 | int lson[M],rson[M],c[M]; 6 | int build(int l,int r) 7 | { 8 | int rt = tot++; 9 | c[rt] = 0; 10 | if(l != r) 11 | { 12 | int mid = l+r>>1; 13 | lson[rt] = build(l,mid); 14 | rson[rt] = build(mid+1,r); 15 | } 16 | return rt; 17 | } 18 | int insert(int rt,int pos,int val) 19 | { 20 | int nrt = tot++, tmp = nrt; 21 | int l = 1, r = m; 22 | c[nrt] = c[rt] + val; 23 | while(l < r) 24 | { 25 | int mid = l+r>>1; 26 | if(pos <= mid) 27 | { 28 | lson[nrt] = tot++; 29 | rson[nrt] = rson[rt]; 30 | nrt = lson[nrt]; 31 | rt = lson[rt]; 32 | r = mid; 33 | } 34 | else 35 | { 36 | rson[nrt] = tot++; 37 | lson[nrt] = lson[rt]; 38 | nrt = rson[nrt]; 39 | rt = rson[rt]; 40 | l = mid+1; 41 | } 42 | c[nrt] = c[rt] + val; 43 | } 44 | return tmp; 45 | } 46 | inline int lowbit(int x) 47 | { 48 | return x&(-x); 49 | } 50 | int sum(int x) 51 | { 52 | int ans = 0; 53 | while(x > 0) 54 | { 55 | ans += c[lson[use[x]]]; 56 | x -= lowbit(x); 57 | } 58 | return ans; 59 | } 60 | void update(int x,int p,int d) 61 | { 62 | while(x <= N) 63 | { 64 | S[x] = insert(S[x],p,d); 65 | x += lowbit(x); 66 | } 67 | } 68 | int query(int L,int R,int k) 69 | { 70 | int lrt = T[L-1]; 71 | int rrt = T[R]; 72 | int l = 1, r = m; 73 | for(int i = L-1; i; i -= lowbit(i)) use[i] = S[i]; 74 | for(int i = R; i ; i -= lowbit(i)) use[i] = S[i]; 75 | while(l < r) 76 | { 77 | int mid = l+r>>1; 78 | int tmp = sum(R) - sum(L-1) + c[lson[rrt]] - c[lson[lrt]]; 79 | if(tmp >= k) 80 | { 81 | r = mid; 82 | for(int i = L-1; i ; i -= lowbit(i)) 83 | use[i] = lson[use[i]]; 84 | for(int i = R; i; i -= lowbit(i)) 85 | use[i] = lson[use[i]]; 86 | lrt = lson[lrt]; 87 | rrt = lson[rrt]; 88 | } 89 | else 90 | { 91 | l = mid+1; 92 | k -= tmp; 93 | for(int i = L-1; i; i -= lowbit(i)) 94 | use[i] = rson[use[i]]; 95 | for(int i = R; i; i -= lowbit(i)) 96 | use[i] = rson[use[i]]; 97 | lrt = rson[lrt]; 98 | rrt = rson[rrt]; 99 | } 100 | } 101 | return l; 102 | } 103 | int op[NV],ql[NV],qr[NV],qk[NV],data[NV]; 104 | void inithash() 105 | { 106 | sort(data+1,data+m+1); 107 | m=unique(data+1,data+m+1)-data; 108 | } 109 | int hash(int x) 110 | { 111 | return lower_bound(data+1,data+m+1,x)-data; 112 | } 113 | void init(int n,int q) 114 | { 115 | N=n; 116 | tot=0; 117 | m=0; 118 | for(int i = 1; i <= n; i++) 119 | scanf("%d",&a[i]),data[++m]=a[i]; 120 | char s[10]; 121 | for(int i = 1; i <= q; i++) 122 | { 123 | scanf("%s",s); 124 | if(s[0] == 'Q') 125 | { 126 | op[i]=0; 127 | scanf("%d%d%d",&ql[i],&qr[i],&qk[i]); 128 | } 129 | else 130 | { 131 | op[i]=1; 132 | scanf("%d%d",&ql[i],&data[++m]); 133 | qk[i]=data[m]; 134 | } 135 | } 136 | inithash(); 137 | T[0] = build(1,m); 138 | for(int i = 1; i <= n; i++) 139 | T[i] = insert(T[i-1],hash(a[i]),1); 140 | for(int i = 1; i <= n; i++) 141 | S[i] = T[0]; 142 | } 143 | int main() 144 | { 145 | int t; 146 | cin>>t; 147 | while(t--) 148 | { 149 | int n,q; 150 | scanf("%d%d",&n,&q); 151 | init(n,q); 152 | for(int i = 1; i <= q; i++) 153 | { 154 | if(op[i]) 155 | { 156 | update(ql[i],hash(a[ql[i]]),-1); 157 | update(ql[i],hash(qk[i]),1); 158 | a[ql[i]]=qk[i]; 159 | } 160 | else printf("%d\n",data[query(ql[i],qr[i],qk[i])]); 161 | } 162 | } 163 | return 0; 164 | } 165 | -------------------------------------------------------------------------------- /模板/4_数据结构/9_可持久化线段树/3_POJ2104.cpp: -------------------------------------------------------------------------------- 1 | #define lson l,m 2 | #define rson m+1,r 3 | const int NV = 100005; 4 | const int NN = NV*25; 5 | int sum[NN],ln[NN],rn[NN]; 6 | int tot,root[NV]; 7 | void PushUp(int k) 8 | { 9 | sum[k]=sum[ln[k]]+sum[rn[k]]; 10 | } 11 | int build(int l,int r) 12 | { 13 | int k=++tot; 14 | if (l == r) 15 | { 16 | sum[k]=0; 17 | return k; 18 | } 19 | int m = (l + r) >> 1; 20 | ln[k]=build(lson); 21 | rn[k]=build(rson); 22 | PushUp(k); 23 | return k; 24 | } 25 | int update(int o,int L,int c,int l,int r) 26 | { 27 | int k=++tot; 28 | sum[k]=sum[o]; 29 | ln[k]=ln[o]; 30 | rn[k]=rn[o]; 31 | if (L == l && l == r) 32 | { 33 | sum[k]+=c; 34 | return k; 35 | } 36 | int m = (l + r) >> 1; 37 | if (L <= m) ln[k]=update(ln[o], L, c, lson); 38 | else rn[k]=update(rn[o], L, c, rson); 39 | PushUp(k); 40 | return k; 41 | } 42 | int query(int a,int b,int L,int l,int r) 43 | { 44 | if (l==r) return l; 45 | int m = (l + r) >> 1; 46 | int tmp=sum[ln[b]]-sum[ln[a]]; 47 | if (L <= tmp) return query(ln[a], ln[b], L, lson); 48 | return query(rn[a], rn[b], L-tmp, rson); 49 | } 50 | int discrete(int data[],int n,int dis[],int idx[]) 51 | { 52 | int sub[n+1]; 53 | memcpy(sub,data,sizeof(sub)); 54 | sort(sub+1,sub+n+1); 55 | int m=unique(sub+1,sub+n+1)-sub-1; 56 | for(int i=1; i<=n; i++) 57 | { 58 | dis[i]=lower_bound(sub+1,sub+m+1,data[i])-sub; 59 | idx[dis[i]]=data[i]; 60 | } 61 | return m; 62 | } 63 | int a[NV],dis[NV],idx[NV]; 64 | int main() 65 | { 66 | int n,m; 67 | scanf("%d%d",&n,&m); 68 | for (int i=1; i<=n; i++) 69 | scanf("%d",&a[i]); 70 | discrete(a,n,dis,idx); 71 | root[0]=build(1,n); 72 | for (int i=1; i<=n; i++) 73 | root[i]=update(root[i-1],dis[i],1,1,n); 74 | while(m--) 75 | { 76 | int aa,bb,k; 77 | scanf("%d%d%d",&aa,&bb,&k); 78 | printf("%d\n",idx[query(root[aa-1],root[bb],k,1,n)]); 79 | } 80 | return 0; 81 | } 82 | -------------------------------------------------------------------------------- /模板/4_数据结构/9_可持久化线段树/4_HDU4866.cpp: -------------------------------------------------------------------------------- 1 | #define lson l,m 2 | #define rson m+1,r 3 | const int NV = 200005; 4 | const int NN = NV*25; 5 | int cnt[NN],ln[NN],rn[NN]; 6 | long long sum[NN]; 7 | int tot,root[NV]; 8 | void PushUp(int k) 9 | { 10 | sum[k]=sum[ln[k]]+sum[rn[k]]; 11 | cnt[k]=cnt[ln[k]]+cnt[rn[k]]; 12 | } 13 | int build(int l,int r) 14 | { 15 | int k=++tot; 16 | if (l == r) 17 | { 18 | sum[k]=0; 19 | cnt[k]=0; 20 | return k; 21 | } 22 | int m = (l + r) >> 1; 23 | ln[k]=build(lson); 24 | rn[k]=build(rson); 25 | PushUp(k); 26 | return k; 27 | } 28 | int M,data[NV]; 29 | int update(int o,int L,int c,int l,int r) 30 | { 31 | int k=++tot; 32 | sum[k]=sum[o]; 33 | cnt[k]=cnt[o]; 34 | ln[k]=ln[o]; 35 | rn[k]=rn[o]; 36 | if (L == l && l == r) 37 | { 38 | sum[k]+=c*data[l]; 39 | cnt[k]+=c; 40 | return k; 41 | } 42 | int m = (l + r) >> 1; 43 | if (L <= m) ln[k]=update(ln[o], L, c, lson); 44 | else rn[k]=update(rn[o], L, c, rson); 45 | PushUp(k); 46 | return k; 47 | } 48 | long long query(int a,int L,int l,int r) 49 | { 50 | if (l==r) return (long long)data[l]*L; //注意不能是sum[a] 51 | int m = (l + r) >> 1; 52 | if (L <= cnt[ln[a]]) return query(ln[a], L, lson); 53 | return sum[ln[a]]+query(rn[a], L-cnt[ln[a]], rson); 54 | } 55 | int inithash(int n) 56 | { 57 | sort(data+1,data+n+1); 58 | return unique(data+1,data+n+1)-data-1; 59 | } 60 | int hash(int x) 61 | { 62 | return lower_bound(data+1,data+M+1,x)-data; 63 | } 64 | struct node 65 | { 66 | int d,x; 67 | node(int d=0,int x=0):d(d),x(x) {} 68 | int sgn() const 69 | { 70 | if (d>0) return 1; 71 | if (d==0) return 0; 72 | return -1; 73 | } 74 | bool operator <(const node &b) const 75 | { 76 | if (x!=b.x) return xb.sgn(); 78 | return abs(d)0) root[i]=update(root[i-1],hash(d),1,1,M); 107 | else root[i]=update(root[i-1],hash(-d),-1,1,M); 108 | } 109 | long long pre=1; 110 | while(m--) 111 | { 112 | int X,aa,bb,cc; 113 | scanf("%d%d%d%d",&X,&aa,&bb,&cc); 114 | int k=(aa%cc*pre%cc+bb)%cc; 115 | int p=lower_bound(a+1,a+2*n+1,node(0,X))-a-1; 116 | long long ans; 117 | if (k) ans=query(root[p],k,1,M); 118 | else ans=0; 119 | if (pre>P) ans*=2; 120 | pre=ans; 121 | printf("%I64d\n",ans); 122 | } 123 | } 124 | return 0; 125 | } 126 | -------------------------------------------------------------------------------- /模板/4_数据结构/9_可持久化线段树/4_HDU4866.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zheng-fan/ACM-ICPC-Template/d66826512103ef35e1436b68f7ee2201cb3bff09/模板/4_数据结构/9_可持久化线段树/4_HDU4866.jpg -------------------------------------------------------------------------------- /模板/5_字符串.tex: -------------------------------------------------------------------------------- 1 | \section{字符串} 2 | \subsection{KMP} 3 | \lstinputlisting{"./模板/5_字符串/1_KMP.cpp"} 4 | 5 | \subsection{扩展KMP} 6 | \lstinputlisting{"./模板/5_字符串/1_扩展KMP.cpp"} 7 | 8 | \subsection{trie字典树} 9 | \lstinputlisting{"./模板/5_字符串/2_trie字典树.cpp"} 10 | 11 | \subsection{AC自动机} 12 | \lstinputlisting{"./模板/5_字符串/3_AC自动机.cpp"} 13 | 14 | \input ./模板/5_字符串/4_哈希.tex 15 | 16 | \subsection{字符串的最小表示法} 17 | \lstinputlisting{"./模板/5_字符串/5_字符串的最小表示法.cpp"} 18 | -------------------------------------------------------------------------------- /模板/5_字符串/1_KMP.cpp: -------------------------------------------------------------------------------- 1 | const int LEN=1000005; 2 | int next[LEN]; 3 | char s[LEN]; 4 | char sub[LEN]; 5 | void getnext(char sub[],int next[],int len2) 6 | { 7 | int i=0,j=-1; 8 | next[0]=-1; 9 | while(i=len2) return i-len2; 26 | else return -1; 27 | } 28 | -------------------------------------------------------------------------------- /模板/5_字符串/1_扩展KMP.cpp: -------------------------------------------------------------------------------- 1 | const int LEN = 100005; 2 | char s[LEN], sub[LEN]; 3 | int next[LEN], ret[LEN]; 4 | void exkmp(char *a, char *b, int M, int N, int *next, int *ret) 5 | { 6 | int i, j, k; 7 | //得到A关于A的后缀的最长公共前缀,存在next数组中 8 | for (j = 0; 1 + j < M && a[j] == a[1 + j]; j++) ; 9 | next[1] = j; 10 | k = 1; 11 | for (i = 2; i < M; i++) 12 | { 13 | int len = k + next[k], L = next[i - k]; 14 | if (L < len - i) next[i] = L; 15 | else 16 | { 17 | for (j = max(0, len - i); i + j < M && a[j] == a[i + j]; j++) ; 18 | next[i] = j; 19 | k = i; 20 | } 21 | } 22 | //得到A关于B的后缀的最长公共前缀,存在ret数组中 23 | for (j = 0; j < N && j < M && a[j] == b[j]; j++) ; 24 | ret[0] = j; 25 | k = 0; 26 | for (i = 1; i < N; i++) 27 | { 28 | int len = k + ret[k], L = next[i - k]; 29 | if (L < len - i) ret[i] = L; 30 | else 31 | { 32 | for (j = max(0, len - i); j < M && i + j < N && a[j] == b[i + j]; j++) ; 33 | ret[i] = j; 34 | k = i; 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /模板/5_字符串/2_trie字典树.cpp: -------------------------------------------------------------------------------- 1 | const int NS=1005*25; 2 | int c[NS][128]; 3 | struct trie 4 | { 5 | // int val[NS]; 6 | int cnt[NS]; 7 | int sz; 8 | trie() 9 | { 10 | sz=1; 11 | memset(c[0],0,sizeof(c[0])); 12 | memset(cnt,0,sizeof(cnt)); 13 | } 14 | void insert(char s[],int v=0) 15 | { 16 | int u=0; 17 | for (int i=0; s[i]; i++) 18 | { 19 | if (!c[u][s[i]]) 20 | { 21 | memset(c[sz],0,sizeof(c[sz])); 22 | // val[sz]=0; 23 | c[u][s[i]]=sz++; 24 | } 25 | u=c[u][s[i]]; 26 | cnt[u]++; 27 | } 28 | // val[u]=v; 29 | } 30 | int query(char s[]) 31 | { 32 | int u=0,n=strlen(s); 33 | for (int i=0; i q; 32 | fail[root] = root; 33 | for(int i = 0; i < 26; i++) 34 | if(next[root][i] == -1) 35 | next[root][i] = root; 36 | else 37 | { 38 | fail[next[root][i]] = root; 39 | q.push(next[root][i]); 40 | } 41 | while(!q.empty()) 42 | { 43 | int now = q.front(); 44 | q.pop(); 45 | for(int i = 0; i < 26; i++) 46 | if(next[now][i] == -1) 47 | next[now][i] = next[fail[now]][i]; 48 | else 49 | { 50 | fail[next[now][i]]=next[fail[now]][i]; 51 | q.push(next[now][i]); 52 | } 53 | } 54 | } 55 | int query(char buf[]) 56 | { 57 | int len = strlen(buf); 58 | int now = root; 59 | int res = 0; 60 | for(int i = 0; i < len; i++) 61 | { 62 | now = next[now][buf[i]-'a']; 63 | int temp = now; 64 | while(temp != root) 65 | { 66 | res += ed[temp]; 67 | ed[temp] = 0; 68 | temp = fail[temp]; 69 | } 70 | } 71 | return res; 72 | } 73 | void Debug() 74 | { 75 | for(int i = 0; i < L; i++) 76 | { 77 | printf("id = %3d,fail = %3d,end = %3d,chi = [",i,fail[i],ed[i]); 78 | for(int j = 0; j < 26; j++) 79 | printf("%2d",next[i][j]); 80 | printf("]\n"); 81 | } 82 | } 83 | }; 84 | char buf[1000010]; 85 | trie ac; 86 | int main() 87 | { 88 | int t; 89 | int n; 90 | scanf("%d",&t); 91 | while(t--) 92 | { 93 | scanf("%d",&n); 94 | ac.init(); 95 | for(int i = 0; i < n; i++) 96 | { 97 | scanf("%s",buf); 98 | ac.insert(buf); 99 | } 100 | ac.build(); 101 | scanf("%s",buf); 102 | printf("%d\n",ac.query(buf)); 103 | } 104 | return 0; 105 | } 106 | -------------------------------------------------------------------------------- /模板/5_字符串/4_哈希.tex: -------------------------------------------------------------------------------- 1 | \subsection{哈希} 2 | \subsubsection{字符串哈希} 3 | \lstinputlisting{"./模板/5_字符串/4_哈希/1_字符串哈希.cpp"} 4 | 5 | \subsubsection{字符串矩阵哈希} 6 | \lstinputlisting{"./模板/5_字符串/4_哈希/2_字符串矩阵哈希.cpp"} 7 | 8 | \subsubsection{哈希函数} 9 | \lstinputlisting{"./模板/5_字符串/4_哈希/3_哈希函数.cpp"} 10 | -------------------------------------------------------------------------------- /模板/5_字符串/4_哈希/1_字符串哈希.cpp: -------------------------------------------------------------------------------- 1 | const int LEN=100005; 2 | unsigned long long f[LEN],r[LEN],pw[LEN]; 3 | int len; 4 | void init(char *s) 5 | { 6 | pw[0]=1; 7 | len=1; 8 | f[0]=s[0]; 9 | for (int i=1; s[i]; i++) 10 | f[i] = f[i-1] * 131 + s[i],len++,pw[i]=pw[i-1]*131; 11 | r[len-1]=s[len-1]; 12 | for (int i=len-2; i>=0; i--) 13 | r[i] = r[i+1] * 131 + s[i]; 14 | } 15 | unsigned long long fwd(int i,int j) 16 | { 17 | if (i<0||j>=len) return 0; 18 | if (i==0) return f[j]; 19 | return f[j]-f[i-1]*pw[j-i+1]; 20 | } 21 | unsigned long long rev(int i,int j) 22 | { 23 | if (i<0||j>=len) return 0; 24 | if (j==len-1) return r[i]; 25 | return r[i]-r[j+1]*pw[j-i+1]; 26 | } 27 | -------------------------------------------------------------------------------- /模板/5_字符串/4_哈希/2_字符串矩阵哈希.cpp: -------------------------------------------------------------------------------- 1 | const int NN=1005; 2 | const int NM=1005; 3 | unsigned long long hash[NN][NM],pw1[NM],pw2[NN],seed1=131,seed2=1313; 4 | void init(char s[][NM],int n,int m) 5 | { 6 | int mx=max(n,m); 7 | pw1[0]=pw2[0]=1; 8 | for (int i=1; i<=m; i++) 9 | pw1[i]=pw1[i-1]*seed1; 10 | for (int i=1; i<=n; i++) 11 | pw2[i]=pw2[i-1]*seed2; 12 | hash[0][1]=hash[1][0]=hash[0][0]=0; 13 | for (int i=1; i<=n; i++) 14 | { 15 | for (int j=1; j<=m; j++) 16 | hash[i][j] = hash[i][j-1] * seed1 + s[i][j]; 17 | for (int j=1; j<=m; j++) 18 | hash[i][j] = hash[i-1][j] * seed2 + hash[i][j]; 19 | } 20 | } 21 | unsigned long long query(int x,int y,int xx,int yy,int n,int m) 22 | { 23 | if (x<1||x>n||xx<1||x>n||y<1||y>m||yy<1||yy>m||x>xx||y>yy) 24 | return 0; 25 | unsigned long long t1,t2; 26 | t1=hash[xx][y-1]-hash[x-1][y-1]*pw2[xx-x+1]; 27 | t2=hash[xx][yy]-hash[x-1][yy]*pw2[xx-x+1]; 28 | return t2-t1*pw1[yy-y+1]; 29 | } 30 | -------------------------------------------------------------------------------- /模板/5_字符串/4_哈希/3_哈希函数.cpp: -------------------------------------------------------------------------------- 1 | // BKDR Hash Function 2 | unsigned long long BKDRHash(char *str) 3 | { 4 | unsigned long long seed = 131; // 31 131 1313 13131 131313 etc.. 5 | unsigned long long hash = 0; 6 | while (*str) 7 | hash = hash * seed + (*str++); 8 | return hash; 9 | } 10 | 11 | // BKDR Hash Function 12 | unsigned int BKDRHash(char *str) 13 | { 14 | unsigned int seed = 131; // 31 131 1313 13131 131313 etc.. 15 | unsigned int hash = 0; 16 | while (*str) 17 | hash = hash * seed + (*str++); 18 | return (hash & 0x7FFFFFFF); 19 | } 20 | 21 | // AP Hash Function 22 | unsigned int APHash(char *str) 23 | { 24 | unsigned int hash = 0; 25 | for (int i=0; *str; i++) 26 | { 27 | if ((i & 1) == 0) 28 | { 29 | hash ^= ((hash << 7) ^ (*str++) ^ (hash >> 3)); 30 | } 31 | else 32 | { 33 | hash ^= (~((hash << 11) ^ (*str++) ^ (hash >> 5))); 34 | } 35 | } 36 | return (hash & 0x7FFFFFFF); 37 | } 38 | 39 | // DJB Hash Function 40 | unsigned int DJBHash(char *str) 41 | { 42 | unsigned int hash = 5381; 43 | while (*str) 44 | hash += (hash << 5) + (*str++); 45 | return (hash & 0x7FFFFFFF); 46 | } 47 | 48 | // JS Hash Function 49 | unsigned int JSHash(char *str) 50 | { 51 | unsigned int hash = 1315423911; 52 | while (*str) 53 | { 54 | hash ^= ((hash << 5) + (*str++) + (hash >> 2)); 55 | } 56 | return (hash & 0x7FFFFFFF); 57 | } 58 | 59 | // RS Hash Function 60 | unsigned int RSHash(char *str) 61 | { 62 | unsigned int b = 378551; 63 | unsigned int a = 63689; 64 | unsigned int hash = 0; 65 | while (*str) 66 | { 67 | hash = hash * a + (*str++); 68 | a *= b; 69 | } 70 | return (hash & 0x7FFFFFFF); 71 | } 72 | 73 | unsigned int SDBMHash(char *str) 74 | { 75 | unsigned int hash = 0; 76 | while (*str) 77 | { 78 | // equivalent to: hash = 65599*hash + (*str++); 79 | hash = (*str++) + (hash << 6) + (hash << 16) - hash; 80 | } 81 | return (hash & 0x7FFFFFFF); 82 | } 83 | 84 | // P. J. Weinberger Hash Function 85 | unsigned int PJWHash(char *str) 86 | { 87 | unsigned int BitsInUnignedInt = (unsigned int)(sizeof(unsigned int) * 8); 88 | unsigned int ThreeQuarters = (unsigned int)((BitsInUnignedInt * 3) / 4); 89 | unsigned int OneEighth = (unsigned int)(BitsInUnignedInt / 8); 90 | unsigned int HighBits = (unsigned int)(0xFFFFFFFF) << (BitsInUnignedInt - OneEighth); 91 | unsigned int hash = 0; 92 | unsigned int test = 0; 93 | while (*str) 94 | { 95 | hash = (hash << OneEighth) + (*str++); 96 | if ((test = hash & HighBits) != 0) 97 | { 98 | hash = ((hash ^ (test >> ThreeQuarters)) & (~HighBits)); 99 | } 100 | } 101 | return (hash & 0x7FFFFFFF); 102 | } 103 | 104 | // ELF Hash Function 105 | unsigned int ELFHash(char *str) 106 | { 107 | unsigned int hash = 0; 108 | unsigned int x = 0; 109 | while (*str) 110 | { 111 | hash = (hash << 4) + (*str++); 112 | if ((x = hash & 0xF0000000L) != 0) 113 | { 114 | hash ^= (x >> 24); 115 | hash &= ~x; 116 | } 117 | } 118 | return (hash & 0x7FFFFFFF); 119 | } 120 | -------------------------------------------------------------------------------- /模板/5_字符串/5_字符串的最小表示法.cpp: -------------------------------------------------------------------------------- 1 | int getmin(char s[],int len) 2 | { 3 | int i=0,j=1,k=0; 4 | while(i0) i+=k+1; 11 | else j+=k+1; 12 | if (i==j) j++; 13 | k=0; 14 | } 15 | } 16 | return min(i,j); 17 | } 18 | -------------------------------------------------------------------------------- /模板/6_动态规划.tex: -------------------------------------------------------------------------------- 1 | \section{动态规划} 2 | \subsection{最大子段和} 3 | \lstinputlisting{"./模板/6_动态规划/1_最大子段和.cpp"} 4 | 5 | \subsection{二维最大子段和} 6 | \lstinputlisting{"./模板/6_动态规划/2_二维最大子段和.cpp"} 7 | 8 | \subsection{最长上升子序列(LIS)} 9 | \lstinputlisting{"./模板/6_动态规划/3_最长上升子序列(LIS).cpp"} 10 | 11 | \subsection{最长公共子序列(LCS)} 12 | \lstinputlisting{"./模板/6_动态规划/4_最长公共子序列(LCS).cpp"} 13 | 14 | \subsection{最长公共上升子序列(LCIS)} 15 | \lstinputlisting{"./模板/6_动态规划/5_最长公共上升子序列(LCIS).cpp"} 16 | 17 | \subsection{数位DP} 18 | \lstinputlisting{"./模板/6_动态规划/6_数位DP.cpp"} 19 | -------------------------------------------------------------------------------- /模板/6_动态规划/1_最大子段和.cpp: -------------------------------------------------------------------------------- 1 | int a[100005]; 2 | int dp[100005]= {}; 3 | for (int i=1; i<=n; i++) 4 | dp[i]=max(a[i],dp[i-1]+a[i]); 5 | for (int i=2; i<=n; i++) 6 | dp[i]=max(dp[i-1],dp[i]); 7 | ///输出子段起始点 8 | while(scanf("%d",&n),n) 9 | { 10 | for (int i=1; i<=n; i++) 11 | scanf("%d",&a[i]); 12 | memset(dp,-1,sizeof(dp)); 13 | for (int i=1; i<=n; i++) 14 | { 15 | if (dp[i-1]<0) 16 | { 17 | b[i]=i; 18 | dp[i]=a[i]; 19 | } 20 | else 21 | { 22 | b[i]=b[i-1]; 23 | dp[i]=dp[i-1]+a[i]; 24 | } 25 | } 26 | int index,mx=-1; 27 | for (int i=1; i<=n; i++) 28 | if (dp[i]>mx) 29 | { 30 | mx=dp[i]; 31 | index=i; 32 | } 33 | if (mx<0) printf("%d %d %d\n",0,a[1],a[n]); 34 | else printf("%d %d %d\n",mx,a[b[index]],a[index]); 35 | } 36 | -------------------------------------------------------------------------------- /模板/6_动态规划/2_二维最大子段和.cpp: -------------------------------------------------------------------------------- 1 | int main() 2 | { 3 | int t[500][500]; 4 | int n; 5 | while(cin>>n) 6 | { 7 | for (int i=1; i<=n; i++) 8 | for (int j=1; j<=n; j++) 9 | scanf("%d",&t[i][j]); 10 | int a[500][500]= {}; 11 | int mx=0; 12 | for (int i=1; i<=n; i++) 13 | { 14 | for (int j=1; j<=n; j++) 15 | a[i][j]+=t[i][j]+a[i-1][j]; 16 | for (int j=1; j<=i; j++) 17 | { 18 | int sum=0; 19 | for (int k=1; k<=n; k++) 20 | { 21 | if (sum<0) 22 | sum=a[i][k]-a[j-1][k]; 23 | else 24 | sum+=a[i][k]-a[j-1][k]; 25 | mx=max(mx,sum); 26 | } 27 | } 28 | } 29 | printf("%d\n",mx); 30 | } 31 | return 0; 32 | } 33 | -------------------------------------------------------------------------------- /模板/6_动态规划/3_最长上升子序列(LIS).cpp: -------------------------------------------------------------------------------- 1 | ///O(n^2) 2 | int dp[5000]= {}; 3 | dp[1]=1; 4 | for (int i=2; i<=n; i++) 5 | { 6 | int mx=0; 7 | for (int j=1; j=dp[ans]) dp[++ans]=a[i]; 23 | else *lower_bound(dp+1,dp+ans+1,a[i])=a[i]; 24 | } 25 | -------------------------------------------------------------------------------- /模板/6_动态规划/4_最长公共子序列(LCS).cpp: -------------------------------------------------------------------------------- 1 | const int LEN=1005; 2 | int dp[LEN][LEN],res; 3 | int a[LEN],b[LEN]; 4 | int n,m; 5 | int lcs() 6 | { 7 | memset(dp,0,sizeof(dp)); 8 | for (int i=1; i<=n; i++) 9 | for (int j=1; j<=m; j++) 10 | if (a[i]==b[j]) dp[i][j]=dp[i-1][j-1]+1; 11 | else dp[i][j]=max(dp[i-1][j],dp[i][j-1]); 12 | return res=dp[n][m]; 13 | } 14 | int ans[LEN]; 15 | void getans() 16 | { 17 | int num=res; 18 | for (int i=n,j=m; i>=1&&j>=1;) 19 | if (a[i]==b[j]) 20 | { 21 | ans[num--]=a[i]; 22 | i--; 23 | j--; 24 | } 25 | else 26 | { 27 | if (dp[i-1][j]>dp[i][j-1]) i--; 28 | else j--; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /模板/6_动态规划/5_最长公共上升子序列(LCIS).cpp: -------------------------------------------------------------------------------- 1 | const int LEN=1005; 2 | int dp[LEN][LEN],path[LEN][LEN],res; 3 | int a[LEN],b[LEN]; 4 | int n,m,ai,aj; 5 | int lcis() 6 | { 7 | memset(dp,0,sizeof(dp)); 8 | res=0; 9 | for (int i=1; i<=n; i++) 10 | { 11 | int mx=0,t; 12 | for (int j=1; j<=m; j++) 13 | { 14 | dp[i][j]=dp[i-1][j]; 15 | path[i][j]=-1; 16 | if (a[i]>b[j]&&mx>t) 5 | { 6 | int flag=1; 7 | long long n1,a1; 8 | if (t) scanf("%lld%lld",&n1,&a1),t--; 9 | while(t--) 10 | { 11 | long long n2,a2,k1,k2; 12 | scanf("%lld%lld",&n2,&a2); 13 | if (flag==0) 14 | continue; 15 | long long d=exgcd(n1,n2,k1,k2); 16 | if ((a2-a1)%d!=0) 17 | flag=0; 18 | if (flag) 19 | { 20 | k1=(k1*(a2-a1)/d%(n2/d)+n2/d)%(n2/d); 21 | long long a=n1*k1+a1; 22 | long long n=n1/d*n2; 23 | n1=n; 24 | a1=a; 25 | } 26 | } 27 | if (flag) return a1; 28 | else return -1; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /模板/7_数论/12_组合数打表.cpp: -------------------------------------------------------------------------------- 1 | const int CN=20; 2 | long long c[CN][CN]= {}; 3 | void cinit() 4 | { 5 | for(int i=0; i1) 15 | ans=ans/n*(n-1); 16 | return ans; 17 | } 18 | long long quickpow(long long a, long long b, long long c) 19 | { 20 | if(b < 0) return 0; 21 | long long ret = 1; 22 | a %= c; 23 | for (; b; b >>= 1, a = (a * a) % c) 24 | if (b & 1) 25 | ret = (ret * a) % c; 26 | return ret; 27 | } 28 | long long solve(long long a[],int i,int n,long long c) 29 | { 30 | if (i==n) 31 | return a[i]%c; 32 | long long p=phi(c); 33 | return quickpow(a[i],solve(a,i+1,n,p)%p+p,c); 34 | } 35 | int main() 36 | { 37 | int m,n; 38 | int cas=0; 39 | while(scanf("%d%d",&m,&n)!=0) 40 | { 41 | long long a[50]; 42 | for (int i=1; i<=n; i++) 43 | scanf("%lld",&a[i]); 44 | printf("Case #%d: %lld\n",++cas,solve(a,1,n,m)); 45 | } 46 | return 0; 47 | } 48 | -------------------------------------------------------------------------------- /模板/7_数论/15_指数循环节.tex: -------------------------------------------------------------------------------- 1 | $$a^b\ mod\ c=a^{b\ mod\ phi(c)+phi(c)}\ mod\ c$$ 2 | 输入$m, n, a_1, a_2, a_3, \cdots, a_n$,求$a_1\string^a_2\string^a_3\string^\cdots\string^a_n\ mod\ m$ 3 | -------------------------------------------------------------------------------- /模板/7_数论/16_Miller_Rabbin大素数测试.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Miller_Rabbin大素数测试 3 | (不能计算long * long) 4 | 复杂度:O(logN) * 测试次数 5 | */ 6 | long long pow_mod(long long a, long long x, long long p) 7 | { 8 | long long res = 1; 9 | while(x) 10 | { 11 | if (x & 1) res = res * a % p; 12 | x >>= 1; 13 | a = a * a % p; 14 | } 15 | return res; 16 | } 17 | bool test(long long n, long long a, long long d) 18 | { 19 | if (n == 2) return true; 20 | if (n == a) return true; 21 | if ((n & 1) == 0) return false; 22 | while(!(d & 1)) d = d >> 1; 23 | long long t = pow_mod(a, d, n); 24 | while((d != n - 1) && (t != 1) && (t != n - 1)) 25 | { 26 | t = t * t % n; 27 | d = d << 1; 28 | } 29 | return (t == n - 1 || (d & 1) == 1); 30 | } 31 | bool Miller_Rabbin(long long n) 32 | { 33 | if (n < 2) return false; 34 | int a[] = {2, 7, 61}; //测试集 35 | for (int i = 0; i <= 2; i++) 36 | if (!test(n, a[i], n - 1)) return false; 37 | return true; 38 | } 39 | 40 | 41 | /* 42 | Miller_Rabbin 算法进行素数测试 43 | 速度快,而且可以判断 <2^63的数 44 | 复杂度:O(logN) * 测试次数 由于要处理long * long,所以略慢 45 | */ 46 | const int S = 20; //随机算法判定次数,S越大,判错概率越小 47 | 48 | //计算 (a*b)%c. a,b都是long long的数,直接相乘可能溢出的 49 | // a,b,c <2^63 50 | long long mult_mod(long long a, long long b, long long c) 51 | { 52 | a %= c; 53 | b %= c; 54 | long long ret = 0; 55 | while(b) 56 | { 57 | if(b & 1) 58 | { 59 | ret += a; 60 | ret %= c; 61 | } 62 | a <<= 1; 63 | if(a >= c)a %= c; 64 | b >>= 1; 65 | } 66 | return ret; 67 | } 68 | 69 | //计算 x^n %c 70 | long long pow_mod(long long x, long long n, long long mod) //x^n%c 71 | { 72 | if(n == 1)return x % mod; 73 | x %= mod; 74 | long long tmp = x; 75 | long long ret = 1; 76 | while(n) 77 | { 78 | if(n & 1) ret = mult_mod(ret, tmp, mod); 79 | tmp = mult_mod(tmp, tmp, mod); 80 | n >>= 1; 81 | } 82 | return ret; 83 | } 84 | 85 | //以a为基,n-1=x*2^t a^(n-1)=1(mod n) 验证n是不是合数 86 | //一定是合数返回true,不一定返回false 87 | bool check(long long a, long long n, long long x, long long t) 88 | { 89 | long long ret = pow_mod(a, x, n); 90 | long long last = ret; 91 | for(int i = 1; i <= t; i++) 92 | { 93 | ret = mult_mod(ret, ret, n); 94 | if(ret == 1 && last != 1 && last != n - 1) return true; //合数 95 | last = ret; 96 | } 97 | if(ret != 1) return true; 98 | return false; 99 | } 100 | 101 | // Miller_Rabin()算法素数判定 102 | //是素数返回true.(可能是伪素数,但概率极小) 103 | //合数返回false; 104 | bool Miller_Rabbin(long long n) 105 | { 106 | if(n < 2)return false; 107 | if(n == 2)return true; 108 | if((n & 1) == 0) return false; //偶数 109 | long long x = n - 1; 110 | long long t = 0; 111 | while((x & 1) == 0) 112 | { 113 | x >>= 1; 114 | t++; 115 | } 116 | for(int i = 0; i < S; i++) 117 | { 118 | long long a = rand() % (n - 1) + 1; 119 | if(check(a, n, x, t)) 120 | return false;//合数 121 | } 122 | return true; 123 | } 124 | -------------------------------------------------------------------------------- /模板/7_数论/1_筛法打质数表.cpp: -------------------------------------------------------------------------------- 1 | const int NP=1000005; 2 | int ispri[NP]= {},prime[NP],pcnt=0; 3 | void getprime() 4 | { 5 | ispri[0]=ispri[1]=1; 6 | for (long long i=2; i0); 23 | if (s==1)s=2; 24 | for (long long j=s; j*prime[i]<=r; j++) 25 | if(j*prime[i]>=l) 26 | iispri[j*prime[i]-l]=1; 27 | } 28 | icnt=0; 29 | for(int i=0; i<=r-l; i++) 30 | if(!iispri[i]) 31 | iprime[++icnt]=i+l; 32 | } 33 | -------------------------------------------------------------------------------- /模板/7_数论/3_分解质因数.cpp: -------------------------------------------------------------------------------- 1 | int a[1000000]= {},pcnt=0; 2 | void pdec(int n) 3 | { 4 | for (int i=1; prime[i]*prime[i]<=n; i++) 5 | if (n%prime[i]==0) 6 | { 7 | a[++pcnt]=prime[i]; 8 | n/=prime[i]; 9 | i--; 10 | } 11 | if (n!=1) a[++pcnt]=n; 12 | } 13 | -------------------------------------------------------------------------------- /模板/7_数论/4_因数个数打表.cpp: -------------------------------------------------------------------------------- 1 | int y[500005]= {}; 2 | void getfactor(int n) 3 | { 4 | int x=sqrt(n); 5 | for (int i=1; i<=x; i++) 6 | { 7 | for (int j=i+1; j*i<=n; j++) 8 | y[i*j]+=2; 9 | y[i*i]++; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /模板/7_数论/5_快速乘法.cpp: -------------------------------------------------------------------------------- 1 | const long long M=1000000007; 2 | long long quickmul(long long a, long long b) 3 | { 4 | long long ret = 0; 5 | for (; b; b >>= 1, a = (a << 1) % M) 6 | if (b & 1) 7 | ret = (ret + a) % M; 8 | return ret; 9 | } 10 | 11 | ///What the fuck is this??!! It works!! 12 | long long quickmul(long long a,long long b) 13 | { 14 | return (a*b-(long long)(a/(long double)M*b+1e-3)*M+M)%M; 15 | } 16 | -------------------------------------------------------------------------------- /模板/7_数论/5_快速幂.cpp: -------------------------------------------------------------------------------- 1 | const long long M=1000000007; 2 | long long quickpow(long long a, long long b) 3 | { 4 | if(b < 0) return 0; 5 | long long ret = 1; 6 | a %= M; 7 | for (; b; b >>= 1, a = (a * a) % M) 8 | if (b & 1) 9 | ret = (ret * a) % M; 10 | return ret; 11 | } 12 | -------------------------------------------------------------------------------- /模板/7_数论/6_费马小定理求逆元.cpp: -------------------------------------------------------------------------------- 1 | const long long M=1000000007; 2 | long long quickpow(long long a, long long b) 3 | { 4 | if(b < 0) return 0; 5 | long long ret = 1; 6 | a %= M; 7 | for (; b; b >>= 1, a = (a * a) % M) 8 | if (b & 1) 9 | ret = (ret * a) % M; 10 | return ret; 11 | } 12 | long long inv(long long a) 13 | { 14 | return quickpow(a,M-2); 15 | } 16 | -------------------------------------------------------------------------------- /模板/7_数论/6_费马小定理求逆元.tex: -------------------------------------------------------------------------------- 1 | $M$必须是质数 -------------------------------------------------------------------------------- /模板/7_数论/7_扩展欧几里得.cpp: -------------------------------------------------------------------------------- 1 | long long exgcd(long long a,long long b,long long &x,long long &y) 2 | { 3 | if (b==0) 4 | { 5 | x=1; 6 | y=0; 7 | return a; 8 | } 9 | long long ans=exgcd(b,a%b,x,y); 10 | long long temp=x; 11 | x=y; 12 | y=temp-(a/b)*y; 13 | return ans; 14 | } 15 | -------------------------------------------------------------------------------- /模板/7_数论/8_扩展欧几里得求逆元.cpp: -------------------------------------------------------------------------------- 1 | const long long M=1000000007; 2 | long long exgcd(long long a,long long b,long long &x,long long &y) 3 | { 4 | if (b==0) 5 | { 6 | x=1; 7 | y=0; 8 | return a; 9 | } 10 | long long ans=exgcd(b,a%b,x,y); 11 | long long temp=x; 12 | x=y; 13 | y=temp-(a/b)*y; 14 | return ans; 15 | } 16 | long long inv(long long a) 17 | { 18 | long long x,y; 19 | long long t=exgcd(a,M,x,y); 20 | if(t!=1) 21 | return -1; 22 | return (x%M+M)%M; 23 | } 24 | -------------------------------------------------------------------------------- /模板/7_数论/8_扩展欧几里得求逆元.tex: -------------------------------------------------------------------------------- 1 | 需要与$M$互质 -------------------------------------------------------------------------------- /模板/7_数论/9_欧拉函数.cpp: -------------------------------------------------------------------------------- 1 | long long phi(long long n) 2 | { 3 | long long ans=n; 4 | long long x=sqrt(n); 5 | for (long long i=2; i<=x; i++) 6 | { 7 | if (n%i==0) 8 | { 9 | while(n%i==0) 10 | n/=i; 11 | ans=ans/i*(i-1); 12 | } 13 | } 14 | if (n>1) 15 | ans=ans/n*(n-1); 16 | return ans; 17 | } 18 | -------------------------------------------------------------------------------- /模板/8_图论.tex: -------------------------------------------------------------------------------- 1 | \section{图论} 2 | \subsection{邻接表} 3 | \lstinputlisting{"./模板/8_图论/1_邻接表.cpp"} 4 | 5 | \subsection{spfa} 6 | \lstinputlisting{"./模板/8_图论/2_spfa.cpp"} 7 | 8 | \subsection{dijkstra} 9 | \lstinputlisting{"./模板/8_图论/3_dijkstra.cpp"} 10 | 11 | \subsection{dijkstra+heap} 12 | \lstinputlisting{"./模板/8_图论/4_dijkstra+heap.cpp"} 13 | 14 | \subsection{floyd-warshall} 15 | \lstinputlisting{"./模板/8_图论/5_floyd_warshall.cpp"} 16 | 17 | \subsection{kruskal} 18 | \lstinputlisting{"./模板/8_图论/6_kruskal.cpp"} 19 | 20 | \subsection{prim} 21 | \lstinputlisting{"./模板/8_图论/7_prim.cpp"} 22 | 23 | \subsection{prim+heap} 24 | \lstinputlisting{"./模板/8_图论/8_prim+heap.cpp"} 25 | 26 | \subsection{最小树形图朱刘算法} 27 | \lstinputlisting{"./模板/8_图论/9_最小树形图朱刘算法.cpp"} 28 | 29 | \subsection{树的直径} 30 | \lstinputlisting{"./模板/8_图论/10_树的直径.cpp"} 31 | 32 | \subsection{二分图最大匹配匈牙利算法} 33 | \input ./模板/8_图论/11_二分图最大匹配匈牙利算法.tex 34 | \lstinputlisting{"./模板/8_图论/11_二分图最大匹配匈牙利算法.cpp"} 35 | 36 | \subsection{网络流Dinic算法} 37 | \lstinputlisting{"./模板/8_图论/12_网络流Dinic算法.cpp"} 38 | 39 | \subsection{LCA的tarjan离线算法} 40 | \lstinputlisting{"./模板/8_图论/13_LCA的tarjan离线算法.cpp"} 41 | 42 | \subsection{2-SAT} 43 | \lstinputlisting{"./模板/8_图论/14_2-SAT_usage.cpp"} 44 | \lstinputlisting{"./模板/8_图论/14_2-SAT.cpp"} 45 | 46 | \subsection{拓扑排序} 47 | \input ./模板/8_图论/15_拓扑排序.tex 48 | -------------------------------------------------------------------------------- /模板/8_图论/10_树的直径.cpp: -------------------------------------------------------------------------------- 1 | typedef int mytype; 2 | const int NV=40005; 3 | const int NE=2*NV; 4 | int vis[NV],he[NV],ecnt; 5 | struct edge 6 | { 7 | int v,next; 8 | mytype l; 9 | } E[NE]; 10 | void adde(int u,int v,mytype l) 11 | { 12 | E[++ecnt].v=v; 13 | E[ecnt].l=l; 14 | E[ecnt].next=he[u]; 15 | he[u]=ecnt; 16 | } 17 | void init(int n,int m) 18 | { 19 | ecnt=0; 20 | memset(he,-1,sizeof(he)); 21 | for (int i=1; i<=m; i++) 22 | { 23 | int u,v; 24 | mytype l; 25 | scanf("%d%d%d",&u,&v,&l); 26 | adde(u,v,l); 27 | adde(v,u,l); 28 | } 29 | } 30 | int U; 31 | mytype L; 32 | void dfs(int u,int uu,mytype l) 33 | { 34 | if (l>L) 35 | { 36 | U=u; 37 | L=l; 38 | } 39 | for (int i=he[u]; i!=-1; i=E[i].next) 40 | if (E[i].v!=uu) 41 | dfs(E[i].v,u,l+E[i].l); 42 | } 43 | mytype solve() 44 | { 45 | dfs(1,0,0); 46 | dfs(U,0,0); 47 | return L; 48 | } 49 | -------------------------------------------------------------------------------- /模板/8_图论/11_二分图最大匹配匈牙利算法.cpp: -------------------------------------------------------------------------------- 1 | const int NV=505; 2 | const int NE=10005; 3 | int he[NV],ecnt,pre[NV],vis[NV]; 4 | struct edge 5 | { 6 | int v,next; 7 | } E[NE]; 8 | void adde(int u,int v) 9 | { 10 | E[++ecnt].v=v; 11 | E[ecnt].next=he[u]; 12 | he[u]=ecnt; 13 | } 14 | int dfs(int u) 15 | { 16 | for(int i=he[u]; i!=-1; i=E[i].next) 17 | { 18 | int v=E[i].v; 19 | if(!vis[v]) 20 | { 21 | vis[v]=1; 22 | if(pre[v]==0||dfs(pre[v])) 23 | { 24 | pre[v]=u; 25 | return 1; 26 | } 27 | } 28 | } 29 | return 0; 30 | } 31 | void init(int m) 32 | { 33 | ecnt=0; 34 | memset(he,-1,sizeof(he)); 35 | memset(pre,0,sizeof(pre)); 36 | while(m--) 37 | { 38 | int u,v; 39 | scanf("%d%d",&u,&v); 40 | adde(u,v); 41 | } 42 | } 43 | int hungary(int n) 44 | { 45 | int ans=0; 46 | for (int i=1; i<=n; i++) 47 | { 48 | memset(vis,0,sizeof(vis)); 49 | ans+=dfs(i); 50 | } 51 | return ans; 52 | } 53 | -------------------------------------------------------------------------------- /模板/8_图论/11_二分图最大匹配匈牙利算法.tex: -------------------------------------------------------------------------------- 1 | 1、一个二分图中的最大匹配数等于这个图中的最小点覆盖数 \\ 2 | König定理是一个二分图中很重要的定理,它的意思是,一个二分图中的最大匹配数等于这个图中的最小点覆盖数。 \\ 3 | 最小点覆盖:假如选了一个点就相当于覆盖了以它为端点的所有边,你需要选择最少的点来覆盖所有的边。 \\ \\ 4 | 2、最小路径覆盖=|G|-最大匹配数 \\ 5 | 在一个$N$*$N$的有向图中,路径覆盖就是在图中找一些路经,使之覆盖了图中的所有顶点,且任何一个顶点有且只有一条路径与之关联。(如果把这些路径中的每条路径从它的起始点走到它的终点,那么恰好可以经过图中的每个顶点一次且仅一次)。如果不考虑图中存在回路,那么每条路径就是一个弱连通子集。 \\ 6 | 由上面可以得出: \\ 7 | 1.一个单独的顶点是一条路径 \\ 8 | 2.如果存在一路径$p_1, p_2, \dots, p_k$,其中$p_1$为起点,$p_k$为终点,那么在覆盖图中,顶点$p_1, p_2, \dots, p_k$不再与其它的顶点之间存在有向边 9 | 最小路径覆盖就是找出最小的路径条数,使之成为G的一个路径覆盖。 \\ \\ 10 | 2、二分图最大独立集=顶点数-最大匹配数 \\ 11 | 独立集:图中任意两个顶点都不相连的顶点集合。 \\ 12 | -------------------------------------------------------------------------------- /模板/8_图论/12_网络流Dinic算法.cpp: -------------------------------------------------------------------------------- 1 | const int NV=20005; 2 | const int NE=500005; 3 | int he[NV],ecnt; 4 | int src,sink; 5 | struct edge 6 | { 7 | int v,next,f; 8 | } E[2*NE]; 9 | void adde(int u,int v,int c) 10 | { 11 | E[++ecnt].v=v; 12 | E[ecnt].f=c; 13 | E[ecnt].next=he[u]; 14 | he[u]=ecnt; 15 | E[++ecnt].v=u; 16 | E[ecnt].f=0; 17 | E[ecnt].next=he[v]; 18 | he[v]=ecnt; 19 | } 20 | void init() 21 | { 22 | ecnt=0; 23 | memset(he,-1,sizeof(he)); 24 | } 25 | queue que; 26 | bool vis[NV]; 27 | int dis[NV]; 28 | void bfs() 29 | { 30 | memset(dis,0,sizeof(dis)); 31 | while(!que.empty()) que.pop(); 32 | vis[src]=1; 33 | que.push(src); 34 | while(!que.empty()) 35 | { 36 | int u=que.front(); 37 | que.pop(); 38 | for (int i=he[u]; i!=-1; i=E[i].next) 39 | if (E[i].f&&!vis[E[i].v]) 40 | { 41 | que.push(E[i].v); 42 | dis[E[i].v]=dis[u]+1; 43 | vis[E[i].v]=1; 44 | } 45 | } 46 | } 47 | int dfs(int u,int delta) 48 | { 49 | if (u==sink) 50 | return delta; 51 | else 52 | { 53 | int ret=0; 54 | for (int i=he[u]; delta&&i!=-1; i=E[i].next) 55 | if (E[i].f&&dis[E[i].v]==dis[u]+1) 56 | { 57 | int dd=dfs(E[i].v,min(E[i].f,delta)); 58 | E[i].f-=dd; 59 | E[(i+1)^1-1].f+=dd; 60 | delta-=dd; 61 | ret+=dd; 62 | } 63 | return ret; 64 | } 65 | } 66 | int maxflow() 67 | { 68 | int ret=0; 69 | while(1) 70 | { 71 | memset(vis,0,sizeof(vis)); 72 | bfs(); 73 | if (!vis[sink]) return ret; 74 | ret+=dfs(src,inf); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /模板/8_图论/13_LCA的tarjan离线算法.cpp: -------------------------------------------------------------------------------- 1 | typedef int mytype; 2 | const int NV=40005; 3 | const int NE=NV; 4 | const int NQ=10005; 5 | mytype dis[NV],ans[NV]; 6 | int vis[NV],he[NV],hq[NV],ecnt,qcnt; 7 | struct edge 8 | { 9 | int v,next; 10 | mytype l; 11 | } E[2*NE]; 12 | struct quer 13 | { 14 | int v,next,i; 15 | } q[2*NQ]; 16 | void adde(int u,int v,mytype l) 17 | { 18 | E[++ecnt].v=v; 19 | E[ecnt].l=l; 20 | E[ecnt].next=he[u]; 21 | he[u]=ecnt; 22 | } 23 | void addq(int u,int v,int i) 24 | { 25 | q[++qcnt].v=v; 26 | q[qcnt].i=i; 27 | q[qcnt].next=hq[u]; 28 | hq[u]=qcnt; 29 | } 30 | int fa[NV],rk[NV]; 31 | void init(int n,int m) 32 | { 33 | ecnt=0; 34 | qcnt=0; 35 | memset(vis,0,sizeof(vis)); 36 | memset(rk,0,sizeof(rk)); 37 | memset(he,-1,sizeof(he)); 38 | memset(hq,-1,sizeof(hq)); 39 | for (int i=1; i<=m; i++) 40 | { 41 | int u,v; 42 | mytype l; 43 | scanf("%d%d%d",&u,&v,&l); 44 | adde(u,v,l); 45 | adde(v,u,l); 46 | } 47 | } 48 | int finds(int x) 49 | { 50 | int k,j,r; 51 | r=x; 52 | while(r!=fa[r]) 53 | r=fa[r]; 54 | k=x; 55 | while(k!=r) 56 | { 57 | j=fa[k]; 58 | fa[k]=r; 59 | k=j; 60 | } 61 | return r; 62 | } 63 | void tarjan(int u,mytype d) 64 | { 65 | dis[u]=d; 66 | fa[u]=u; 67 | vis[u]=1; 68 | for (int i=he[u]; i!=-1; i=E[i].next) 69 | if (!vis[E[i].v]) 70 | tarjan(E[i].v,d+E[i].l),fa[E[i].v]=u; 71 | for (int i=hq[u]; i!=-1; i=q[i].next) 72 | if (vis[q[i].v]) 73 | ans[q[i].i]=dis[u]+dis[q[i].v]-2*dis[finds(q[i].v)]; 74 | } 75 | void solve(int n,int m) 76 | { 77 | init(n,m); 78 | int k; 79 | scanf("%d",&k); 80 | for (int i=1; i<=k; i++) 81 | { 82 | int u,v; 83 | scanf("%d%d",&u,&v); 84 | addq(u,v,i); 85 | addq(v,u,i); 86 | } 87 | tarjan(1,0); 88 | for (int i=1; i<=k; i++) 89 | printf("%d\n",ans[i]); 90 | } 91 | -------------------------------------------------------------------------------- /模板/8_图论/14_2-SAT.cpp: -------------------------------------------------------------------------------- 1 | const int NV=1005; 2 | const int NE=2000005; 3 | int low[2*NV],dfn[2*NV],stk[2*NV],instk[2*NV],he[2*NV],belong[2*NV],sol[2*NV]; 4 | int idcnt,ecnt,ccnt,top; 5 | vector c[2*NV]; 6 | struct edge 7 | { 8 | int v,next; 9 | } E[2*NE]; 10 | void adde(int u,int v) 11 | { 12 | E[++ecnt].v=v; 13 | E[ecnt].next=he[u]; 14 | he[u]=ecnt; 15 | } 16 | int getvalue(int n,int x) 17 | { 18 | int r=x>n?x-n:x; 19 | if (sol[r]==-1) 20 | return -1; 21 | return x>n?!sol[r]:sol[r]; 22 | } 23 | void dfs(int u) 24 | { 25 | low[u]=dfn[u]=++idcnt; 26 | stk[++top]=u; 27 | instk[u]=1; 28 | for (int i=he[u],v; i!=-1; i=E[i].next) 29 | if (!dfn[v=E[i].v]) 30 | { 31 | dfs(v); 32 | low[u]=min(low[u],low[v]); 33 | } 34 | else if (instk[v]) 35 | low[u]=min(low[u],dfn[v]); 36 | if (dfn[u]==low[u]) 37 | { 38 | stk[top+1]=-1; 39 | for (++ccnt; stk[top+1]!=u; --top) 40 | { 41 | c[ccnt].push_back(stk[top]); 42 | instk[stk[top]]=0; 43 | belong[stk[top]]=ccnt; 44 | } 45 | } 46 | } 47 | bool two_sat(int n,int m) 48 | { 49 | ecnt=idcnt=ccnt=top=0; 50 | for (int i=1; i<=2*n; i++) 51 | { 52 | he[i]=-1; 53 | dfn[i]=instk[i]=0; 54 | c[i].clear(); 55 | } 56 | for (int i=1; i<=n; i++) 57 | sol[i]=-1; 58 | for (int i=0; in) 85 | sol[c[i][j]-n]=!val; 86 | else 87 | sol[c[i][j]]=val; 88 | } 89 | return 1; 90 | } 91 | -------------------------------------------------------------------------------- /模板/8_图论/14_2-SAT_usage.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | x 3 | ~x 4 | x&y 5 | ~(x&y) 6 | x|y 7 | ~(x|y) 8 | x^y 9 | ~(x^y) 10 | */ -------------------------------------------------------------------------------- /模板/8_图论/15_拓扑排序.tex: -------------------------------------------------------------------------------- 1 | 一般有两种算法:零入度算法(Kahn)和零出度算法。零入度算法一般用queue实现,类似BFS,但选点顺序不重要。零出度算法一般用DFS实现。\\ 2 | 3 | 零入度算法\\ 4 | 5 | \lstinputlisting{"./模板/8_图论/15_拓扑排序/1_Kahn.cpp"} 6 | 7 | 零出度算法\\ 8 | 9 | \lstinputlisting{"./模板/8_图论/15_拓扑排序/2_DFS.cpp"} 10 | -------------------------------------------------------------------------------- /模板/8_图论/15_拓扑排序/1_Kahn.cpp: -------------------------------------------------------------------------------- 1 | const int NV=10005; 2 | const int NE=20005; 3 | int he[NV],ecnt,ind[NV],ord[NV],acnt; 4 | struct edge 5 | { 6 | int v,next; 7 | } E[NE]; 8 | void adde(int u,int v) 9 | { 10 | E[++ecnt].v=v; 11 | E[ecnt].next=he[u]; 12 | he[u]=ecnt; 13 | ind[v]++; 14 | } 15 | void init(int n,int m) 16 | { 17 | ecnt=0; 18 | acnt=0; 19 | memset(he,-1,sizeof(he)); 20 | memset(ind,0,sizeof(ind)); 21 | for (int i=1; i<=m; i++) 22 | { 23 | int u,v; 24 | scanf("%d%d",&u,&v); 25 | adde(u,v); 26 | } 27 | } 28 | int toposort(int n) 29 | { 30 | queue q; 31 | for (int i=1; i<=n; i++) 32 | if (ind[i]==0) q.push(i); 33 | while(!q.empty()) 34 | { 35 | int u=q.front(); 36 | q.pop(); 37 | ord[++acnt]=u; 38 | for (int i=he[u]; i!=-1; i=E[i].next) 39 | if (ind[E[i].v]) 40 | { 41 | ind[E[i].v]--; 42 | if (ind[E[i].v]==0) q.push(E[i].v); 43 | } 44 | } 45 | if (acnt!=n) return -1; 46 | return acnt; 47 | } 48 | -------------------------------------------------------------------------------- /模板/8_图论/15_拓扑排序/2_DFS.cpp: -------------------------------------------------------------------------------- 1 | const int NV=10005; 2 | const int NE=20005; 3 | int he[NV],ecnt,vis[NV],ord[NV],acnt; ///这里ord顺序是反过来的 4 | struct edge 5 | { 6 | int v,next; 7 | } E[NE]; 8 | void adde(int u,int v) 9 | { 10 | E[++ecnt].v=v; 11 | E[ecnt].next=he[u]; 12 | he[u]=ecnt; 13 | } 14 | void init(int n,int m) 15 | { 16 | ecnt=0; 17 | acnt=0; 18 | memset(he,-1,sizeof(he)); 19 | memset(vis,0,sizeof(vis)); 20 | for (int i=1; i<=m; i++) 21 | { 22 | int u,v; 23 | scanf("%d%d",&u,&v); 24 | adde(u,v); 25 | } 26 | } 27 | int dfs(int u) 28 | { 29 | vis[u]=1; 30 | for (int i=he[u]; i!=-1; i=E[i].next) 31 | { 32 | if (vis[E[i].v]==1) return -1; 33 | else if (!vis[E[i].v]&&dfs(E[i].v)==-1) return -1; 34 | } 35 | vis[u]=2; 36 | ord[++acnt]=u; 37 | return 0; 38 | } 39 | int toposort(int n) 40 | { 41 | for (int i=1; i<=n; i++) 42 | if (!vis[i]&&dfs(i)==-1) 43 | return -1; 44 | return acnt; 45 | } 46 | -------------------------------------------------------------------------------- /模板/8_图论/1_邻接表.cpp: -------------------------------------------------------------------------------- 1 | typedef int mytype; 2 | const int NV=105; 3 | const int NE=10005*2; 4 | int he[NV],ecnt; 5 | struct edge 6 | { 7 | int v,next; 8 | mytype l; 9 | } E[NE]; 10 | void adde(int u,int v,mytype l) 11 | { 12 | E[++ecnt].v=v; 13 | E[ecnt].l=l; 14 | E[ecnt].next=he[u]; 15 | he[u]=ecnt; 16 | } 17 | ///初始化: 18 | ecnt=0; 19 | memset(he,-1,sizeof(he)); 20 | ///调用: 21 | for (int i=he[u]; i!=-1; i=E[i].next) ; 22 | -------------------------------------------------------------------------------- /模板/8_图论/2_spfa.cpp: -------------------------------------------------------------------------------- 1 | typedef int mytype; 2 | const int NV=105; 3 | const int NE=10005*2; 4 | mytype dis[NV]; 5 | int pre[NV],vis[NV],vcnt[NV],he[NV],ecnt,flag; 6 | struct edge 7 | { 8 | int v,next; 9 | mytype l; 10 | } E[NE]; 11 | void adde(int u,int v,mytype l) 12 | { 13 | E[++ecnt].v=v; 14 | E[ecnt].l=l; 15 | E[ecnt].next=he[u]; 16 | he[u]=ecnt; 17 | } 18 | void init(int n,int m,int s) 19 | { 20 | ecnt=0; 21 | memset(pre,0,sizeof(pre)); 22 | memset(vis,0,sizeof(vis)); 23 | memset(vcnt,0,sizeof(vcnt)); 24 | memset(he,-1,sizeof(he)); 25 | for (int i=0; i<=n; i++) 26 | dis[i]=inf; 27 | dis[s]=0; 28 | for (int i=1; i<=m; i++) 29 | { 30 | int u,v; 31 | mytype l; 32 | scanf("%d%d%d",&u,&v,&l); 33 | adde(u,v,l); 34 | adde(v,u,l); 35 | } 36 | } 37 | void spfa(int n,int m,int s) 38 | { 39 | queue q; 40 | vis[s]=1; 41 | q.push(s); 42 | flag=0; 43 | while(!q.empty()) 44 | { 45 | int u=q.front(); 46 | q.pop(); 47 | vis[u]=0; 48 | if(vcnt[u]>=n) 49 | { 50 | flag=1; 51 | break; 52 | } 53 | for (int i=he[u]; i!=-1; i=E[i].next) 54 | if (dis[u]+E[i].lp.l; 44 | } 45 | }; 46 | void dijkstra_heap(int s) 47 | { 48 | priority_queue q; 49 | q.push(point(s,0)); 50 | while(!q.empty()) 51 | { 52 | point p=q.top(); 53 | q.pop(); 54 | int u=p.u; 55 | if (vis[u]) continue; 56 | vis[u]=1; 57 | for (int i=he[u]; i!=-1; i=E[i].next) 58 | if (!vis[E[i].v]&&p.l+E[i].l%d",path[tmp][v]); 35 | tmp=path[tmp][v]; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /模板/8_图论/6_kruskal.cpp: -------------------------------------------------------------------------------- 1 | typedef int mytype; 2 | const int NV=105; 3 | const int NE=10005; 4 | struct edge 5 | { 6 | int u,v; 7 | mytype l; 8 | bool operator<(const edge e) const 9 | { 10 | return lrk[b]) f[b]=a; 24 | else 25 | { 26 | if (rk[a]==rk[b]) rk[b]++; 27 | f[a]=b; 28 | } 29 | } 30 | void init(int n,int m) 31 | { 32 | memset(rk,0,sizeof(rk)); 33 | for (int i=1; i<=n; i++) 34 | f[i]=i; 35 | for (int i=1; i<=m; i++) 36 | scanf("%d%d%d",&E[i].u,&E[i].v,&E[i].l); 37 | } 38 | mytype kruskal(int n,int m) 39 | { 40 | sort(E+1,E+m+1); 41 | mytype ans=0; 42 | for (int i=1; i<=m; i++) 43 | if (finds(E[i].u)!=finds(E[i].v)) 44 | { 45 | uni(E[i].u,E[i].v); 46 | ans+=E[i].l; 47 | } 48 | return ans; 49 | } 50 | bool judge(int n) 51 | { 52 | int flag=0; 53 | for (int i=1; i<=n; i++) 54 | if (finds(i)==i) 55 | flag++; 56 | return flag==1; 57 | } 58 | -------------------------------------------------------------------------------- /模板/8_图论/7_prim.cpp: -------------------------------------------------------------------------------- 1 | typedef int mytype; 2 | const int NV=1005; 3 | int pre[NV],vis[NV]; 4 | mytype dis[NV],g[NV][NV]; 5 | void init(int n,int m,int s) 6 | { 7 | memset(pre,0,sizeof(pre)); 8 | memset(vis,0,sizeof(vis)); 9 | for (int i=0; i<=n; i++) 10 | dis[i]=inf; 11 | dis[s]=0; 12 | for (int i=1; i<=n; i++) 13 | for (int j=1; j<=n; j++) 14 | g[i][j]=inf; 15 | for (int i=1; i<=m; i++) 16 | { 17 | int u,v,l; 18 | scanf("%d%d%d",&u,&v,&l); 19 | g[u][v]=l; 20 | g[v][u]=l; 21 | } 22 | } 23 | mytype prim(int n) 24 | { 25 | mytype ans=0; 26 | for (int i=1; i<=n; i++) 27 | { 28 | int u=0; 29 | for (int j=1; j<=n; j++) 30 | if (!vis[j]&&dis[j]p.l; 44 | } 45 | }; 46 | mytype prim_heap(int s) 47 | { 48 | priority_queue q; 49 | q.push(point(s,0)); 50 | mytype ans=0; 51 | pcnt=0; 52 | while(!q.empty()) 53 | { 54 | point p=q.top(); 55 | q.pop(); 56 | int u=p.u; 57 | if (vis[u]) 58 | continue; 59 | vis[u]=1; 60 | ans+=p.l;//==dis[x] 61 | pcnt++; 62 | for (int i=he[u]; i!=-1; i=E[i].next) 63 | if (!vis[E[i].v]&&E[i].leps; 87 | } 88 | -------------------------------------------------------------------------------- /模板/9_数学.tex: -------------------------------------------------------------------------------- 1 | \section{数学} 2 | \subsection{高斯消元} 3 | \lstinputlisting{"./模板/9_数学/1_高斯消元.cpp"} 4 | 5 | \subsection{二进制下的高斯消元} 6 | \lstinputlisting{"./模板/9_数学/2_二进制下的高斯消元.cpp"} 7 | 8 | \input ./模板/9_数学/3_高精度整数类.tex 9 | 10 | \subsection{分数类} 11 | \input ./模板/9_数学/4_分数类.tex 12 | \lstinputlisting{"./模板/9_数学/4_分数类.cpp"} 13 | 14 | \subsection{矩阵类} 15 | \lstinputlisting{"./模板/9_数学/5_矩阵类.cpp"} 16 | 17 | \subsection{分治法等比数列求和} 18 | \input ./模板/9_数学/6_分治法等比数列求和.tex 19 | \lstinputlisting{"./模板/9_数学/6_分治法等比数列求和.cpp"} 20 | 21 | \subsection{自适应Simpson积分法} 22 | \lstinputlisting{"./模板/9_数学/7_自适应Simpson积分法.cpp"} 23 | 24 | \subsection{Romberg积分法} 25 | \lstinputlisting{"./模板/9_数学/8_Romberg积分法.cpp"} 26 | 27 | \subsection{De Bruijn序列} 28 | \input ./模板/9_数学/9_De_Bruijn序列.tex 29 | \lstinputlisting{"./模板/9_数学/9_De_Bruijn序列.cpp"} 30 | 31 | \subsection{格雷码} 32 | \lstinputlisting{"./模板/9_数学/10_格雷码.cpp"} 33 | 34 | \subsection{表达式求值} 35 | \lstinputlisting{"./模板/9_数学/11_表达式求值.cpp"} 36 | 37 | \subsection{卡特兰数} 38 | \input ./模板/9_数学/12_卡特兰数.tex 39 | 40 | \subsection{求和公式} 41 | \input ./模板/9_数学/13_求和公式.tex 42 | 43 | \subsection{小公式} 44 | \input ./模板/9_数学/14_小公式.tex 45 | 46 | \subsection{快速傅里叶变换} 47 | \input ./模板/9_数学/15_快速傅里叶变换.tex 48 | \lstinputlisting{"./模板/9_数学/15_快速傅里叶变换.cpp"} 49 | -------------------------------------------------------------------------------- /模板/9_数学/10_格雷码.cpp: -------------------------------------------------------------------------------- 1 | vector gray(int n) 2 | { 3 | vector res; 4 | for (unsigned long i=0; i<(1<>1)); 6 | return res; 7 | } 8 | int main() 9 | { 10 | vector v=gray(8); 11 | for (int i=0; i(v[i])< 2 | const int NV=100005; 3 | complex epsilon[NV],repsilon[NV],buffera[NV],bufferb[NV],ffttemp[NV]; 4 | void init_epsilon(int n) 5 | { 6 | for (int i=0; i(cos(2*pi*i/n),sin(2*pi*i/n)); 9 | repsilon[i]=conj(epsilon[i]); 10 | } 11 | } 12 | void fft(int n, complex *buffer, int offset, int step, complex *epsilon) 13 | { 14 | if(n==1) return; 15 | int m=n>>1; 16 | fft(m,buffer,offset,step<<1,epsilon); 17 | fft(m,buffer,offset+step,step<<1,epsilon); 18 | for(int k=0; k>1; 33 | n|=n>>2; 34 | n|=n>>4; 35 | n|=n>>8; 36 | n|=n>>16; 37 | n++; 38 | ///注意a和b要memset或者补零 39 | init_epsilon(n); ///n不变就可以不用重新init 40 | for (int i=0; ifabs(mx)) 11 | mx=a[row=i][k]; 12 | if(fabs(mx)=1; i--) 27 | for(j=i+1; j<=n; j++) 28 | b[i]-=a[i][j]*b[j]; 29 | return 1; 30 | } 31 | -------------------------------------------------------------------------------- /模板/9_数学/2_二进制下的高斯消元.cpp: -------------------------------------------------------------------------------- 1 | const int MAXN=105; 2 | int a[MAXN][MAXN],b[MAXN]; 3 | void gauss(int n,int a[][MAXN],int b[]) 4 | { 5 | for (int i=1; i<=n; i++) 6 | { 7 | int k; 8 | for (int j=i; j<=n; j++) 9 | if (a[j][i]) 10 | { 11 | k=j; 12 | break; 13 | } 14 | for (int j=1; j<=n; j++) 15 | swap(a[i][j],a[k][j]); 16 | swap(b[i],b[k]); 17 | for (int j=1; j<=n; j++) 18 | if (i!=j&&a[j][i]) 19 | { 20 | for (k=1; k<=n; k++) 21 | a[j][k]^=a[i][k]; 22 | b[j]^=b[i]; 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /模板/9_数学/3_高精度整数类.tex: -------------------------------------------------------------------------------- 1 | \subsection{高精度整数类} 2 | 3 | 在进行大数的其他操作时要注意输出字符串为空的情况 \\ 4 | WARNING! integer类型与long long大小的整数进行乘除操作时,非常有可能溢出,尤其是除法。最好使用integer与integer的乘除操作。\\ 5 | 另外,使用integer会产生大量开销,使用适当的数组长度可以很大程度上减少这种开销。\\ 6 | 7 | \subsubsection{栈分配内存版} 8 | \lstinputlisting{"./模板/9_数学/3_高精度整数类/1_stack.cpp"} 9 | 10 | \subsubsection{堆分配内存版} 11 | \lstinputlisting{"./模板/9_数学/3_高精度整数类/2_heap.cpp"} 12 | 13 | \subsubsection{快速傅里叶变换乘法} 14 | \lstinputlisting{"./模板/9_数学/3_高精度整数类/3_FFTmul.cpp"} 15 | 16 | \subsubsection{快速数论变换乘法} 17 | 18 | 关于$r$、$k$、$g$的选值问题:\\ 19 | $2281701377$平方不会超过long long,$1004535809$相加不会超过int。\\ 20 | 21 | \begin{table}[!htbp] 22 | \centering 23 | \begin{tabular}{|l|l|l|l|} 24 | \hline 25 | $r \cdot 2^k + 1$ & $r$ & $k$ & $g$ \\ \hline 26 | $3$ & $1$ & $1$ & $2$ \\ \hline 27 | $5$ & $1$ & $2$ & $2$ \\ \hline 28 | $17$ & $1$ & $4$ & $3$ \\ \hline 29 | $97$ & $3$ & $5$ & $5$ \\ \hline 30 | $193$ & $3$ & $6$ & $5$ \\ \hline 31 | $257$ & $1$ & $8$ & $3$ \\ \hline 32 | $7681$ & $15$ & $9$ & $17$ \\ \hline 33 | $12289$ & $3$ & $12$ & $11$ \\ \hline 34 | $40961$ & $5$ & $13$ & $3$ \\ \hline 35 | $65537$ & $1$ & $16$ & $3$ \\ \hline 36 | $786433$ & $3$ & $18$ & $10$ \\ \hline 37 | $5767169$ & $11$ & $19$ & $3$ \\ \hline 38 | $7340033$ & $7$ & $20$ & $3$ \\ \hline 39 | $23068673$ & $11$ & $21$ & $3$ \\ \hline 40 | $104857601$ & $25$ & $22$ & $3$ \\ \hline 41 | $167772161$ & $5$ & $25$ & $3$ \\ \hline 42 | $469762049$ & $7$ & $26$ & $3$ \\ \hline 43 | $998244353$ & $119$ & $23$ & $3$ \\ \hline 44 | $1004535809$ & $479$ & $21$ & $3$ \\ \hline 45 | $2013265921$ & $15$ & $27$ & $31$ \\ \hline 46 | $2281701377$ & $17$ & $27$ & $3$ \\ \hline 47 | $3221225473$ & $3$ & $30$ & $5$ \\ \hline 48 | $75161927681$ & $35$ & $31$ & $3$ \\ \hline 49 | $77309411329$ & $9$ & $33$ & $7$ \\ \hline 50 | $206158430209$ & $3$ & $36$ & $22$ \\ \hline 51 | $2061584302081$ & $15$ & $37$ & $7$ \\ \hline 52 | $2748779069441$ & $5$ & $39$ & $3$ \\ \hline 53 | $6597069766657$ & $3$ & $41$ & $5$ \\ \hline 54 | $39582418599937$ & $9$ & $42$ & $5$ \\ \hline 55 | $79164837199873$ & $9$ & $43$ & $5$ \\ \hline 56 | $263882790666241$ & $15$ & $44$ & $7$ \\ \hline 57 | $1231453023109121$ & $35$ & $45$ & $3$ \\ \hline 58 | $1337006139375617$ & $19$ & $46$ & $3$ \\ \hline 59 | $3799912185593857$ & $27$ & $47$ & $5$ \\ \hline 60 | $4222124650659841$ & $15$ & $48$ & $19$ \\ \hline 61 | $7881299347898369$ & $7$ & $50$ & $6$ \\ \hline 62 | $31525197391593473$ & $7$ & $52$ & $3$ \\ \hline 63 | $180143985094819841$ & $5$ & $55$ & $6$ \\ \hline 64 | $1945555039024054273$ & $27$ & $56$ & $5$ \\ \hline 65 | $4179340454199820289$ & $29$ & $57$ & $3$ \\ \hline 66 | \end{tabular} 67 | \end{table} 68 | 69 | \lstinputlisting{"./模板/9_数学/3_高精度整数类/4_FNTTmul.cpp"} 70 | -------------------------------------------------------------------------------- /模板/9_数学/3_高精度整数类/3_FFTmul.cpp: -------------------------------------------------------------------------------- 1 | ///由于使用万进制,NV可以除以4。但又由于答案长度是原来的2倍,再加上补到2的某次方的最坏情况是到2倍,因此NV的大小跟数的十进制长度相同即可。 2 | #include 3 | ///使用double也可以 4 | complex epsilon[NV],repsilon[NV],buffera[NV],bufferb[NV],ffttemp[NV]; 5 | void init_epsilon(int n) 6 | { 7 | for (int i=0; i(cos(2*pi*i/n), sin(2*pi*i/n)); 10 | repsilon[i]=conj(epsilon[i]); 11 | } 12 | } 13 | void fft(int n, complex *buffer, int offset, int step, complex *epsilon) 14 | { 15 | if(n==1) return; 16 | int m=n>>1; 17 | fft(m,buffer,offset,step<<1,epsilon); 18 | fft(m,buffer,offset+step,step<<1,epsilon); 19 | for(int k=0; k>1; 36 | n|=n>>2; 37 | n|=n>>4; 38 | n|=n>>8; 39 | n|=n>>16; 40 | n++; 41 | ///似乎也可以1、2调换但1变成n=2*n 42 | init_epsilon(n); 43 | for (int i=0; i1&&ans.d[ans.d[0]]==0) ans.d[0]--; 59 | return ans; 60 | } 61 | -------------------------------------------------------------------------------- /模板/9_数学/3_高精度整数类/4_FNTTmul.cpp: -------------------------------------------------------------------------------- 1 | ///double型的精度有十进制的15位,在万进制下,要存储10000*10000*n以及计算中可能会产生精度问题,可以使用快速数论变换 2 | long long epsilon[NV],repsilon[NV],buffera[NV],bufferb[NV],ffttemp[NV]; 3 | ///p = r * 2^k + 1 4 | ///4179340454199820289 = 29 * 2^57 + 1, g = 3, 要保证fftmul处理后的n<2^k且10000*10000*n>= 1, a = (a << 1) % M) 11 | // if (b & 1) 12 | // ret = (ret + a) % M; 13 | // return ret; 14 | //} 15 | ///下面这个神奇的做法暂时还没发现会出问题的地方,而且效率很高 16 | long long quickmul(long long a,long long b) 17 | { 18 | return (a*b-(long long)(a/(long double)M*b+1e-3)*M+M)%M; 19 | } 20 | long long quickpow(long long a, long long b) 21 | { 22 | if(b < 0) return 0; 23 | long long ret = 1; 24 | a %= M; 25 | for (; b; b >>= 1, a = quickmul(a,a)) 26 | if (b & 1) 27 | ret = quickmul(ret,a); 28 | return ret; 29 | } 30 | long long inv(long long a) 31 | { 32 | return quickpow(a,M-2); 33 | } 34 | void init_epsilon(int n) 35 | { 36 | epsilon[0]=repsilon[0]=1; 37 | long long gr=quickpow(3,(M-1)/n); 38 | for (int i=1; i>1; 48 | fft(m,buffer,offset,step<<1,epsilon); 49 | fft(m,buffer,offset+step,step<<1,epsilon); 50 | for(int k=0; k>1; 65 | n|=n>>2; 66 | n|=n>>4; 67 | n|=n>>8; 68 | n|=n>>16; 69 | n++; 70 | init_epsilon(n); 71 | for (int i=0; i1&&ans.d[ans.d[0]]==0) ans.d[0]--; 87 | return ans; 88 | } 89 | -------------------------------------------------------------------------------- /模板/9_数学/4_分数类.cpp: -------------------------------------------------------------------------------- 1 | struct frac 2 | { 3 | long long num,den; 4 | frac(long long num=0,long long den=1) 5 | { 6 | if (den<0) num=-num,den=-den; 7 | long long g=__gcd(abs(num),den); 8 | this->num=num/g; 9 | this->den=den/g; 10 | } 11 | frac operator +(const frac &o) const 12 | { 13 | return frac(num*o.den+den*o.num,den*o.den); 14 | } 15 | frac operator -(const frac &o) const 16 | { 17 | return frac(num*o.den-den*o.num,den*o.den); 18 | } 19 | frac operator *(const frac &o) const 20 | { 21 | return frac(num*o.num,den*o.den); 22 | } 23 | frac operator /(const frac &o) const 24 | { 25 | return frac(num*o.den,den*o.num); 26 | } 27 | bool operator <(const frac &o) const 28 | { 29 | return num*o.den>= 1, a = (a * a) % M) 10 | if (b & 1) 11 | ret = (ret * a) % M; 12 | return ret; 13 | } 14 | long long inv(long long a) 15 | { 16 | return quickpow(a,M-2); 17 | } 18 | struct mat 19 | { 20 | int n,m; 21 | mytype a[SZ][SZ]; 22 | void init() 23 | { 24 | memset(a,0,sizeof(a)); 25 | } 26 | mat(int n=SZ,int m=SZ):n(n),m(m) {} 27 | mat unit() 28 | { 29 | mat t(n,n); 30 | t.init(); 31 | for (int i=0; i>=1,a=a*a) 102 | if (b&1) 103 | ret=ret*a; 104 | return ret; 105 | } 106 | void in() 107 | { 108 | for (int i=0; i0) 6 | { 7 | if (n&1) 8 | ans=((ans*q)%M+temp%M)%M; 9 | temp=(temp*(1+q))%M; 10 | q=(q*q)%M; 11 | n>>=1; 12 | } 13 | return ans; 14 | } 15 | 16 | mat qsum(mat q,long long n) 17 | { 18 | n++; 19 | mat unit=q.unit(); 20 | mat ans(q.n,q.m),temp=unit; 21 | ans.init(); 22 | while(n>0) 23 | { 24 | if (n&1) ans=ans*q+temp; 25 | temp=temp*(unit+q); 26 | q=q*q; 27 | n>>=1; 28 | } 29 | return ans; 30 | } 31 | -------------------------------------------------------------------------------- /模板/9_数学/6_分治法等比数列求和.tex: -------------------------------------------------------------------------------- 1 | $1+q^1+\cdots+q^n$ -------------------------------------------------------------------------------- /模板/9_数学/7_自适应Simpson积分法.cpp: -------------------------------------------------------------------------------- 1 | double simpson(double a,double b) 2 | { 3 | double c = a + (b-a)/2; 4 | return (f(a)+4*f(c)+f(b))*(b-a)/6; 5 | } 6 | double asr(double a,double b,double epss,double A) 7 | { 8 | double c = a+(b-a)/2; 9 | double L = simpson(a,c), R = simpson(c,b); 10 | if (fabs(L+R-A) <= 15*epss) return L+R+(L+R-A)/15; 11 | return asr(a,c,epss/2,L) + asr(c,b,epss/2,R); 12 | } 13 | double solve(double l,double r) 14 | { 15 | return asr(l,r,eps,simpson(l,r)); 16 | } 17 | -------------------------------------------------------------------------------- /模板/9_数学/8_Romberg积分法.cpp: -------------------------------------------------------------------------------- 1 | double romberg(double l,double r,double epss=eps) 2 | { 3 | vector t; 4 | double h=r-l,last,curr; 5 | int k=1,i=1; 6 | t.push_back(h*(f(l)+f(r))/2); 7 | do 8 | { 9 | last=t.back(); 10 | curr=0; 11 | double x=l+h/2; 12 | for (int j=0; jepss); 33 | return t.back(); 34 | } 35 | -------------------------------------------------------------------------------- /模板/9_数学/9_De_Bruijn序列.cpp: -------------------------------------------------------------------------------- 1 | void db(int n,int k,vector &v,int a[],int t=1,int p=1) 2 | { 3 | if (t>n) 4 | { 5 | if (n%p==0) 6 | for (int i=1; i<=p; i++) 7 | v.push_back(a[i]); 8 | } 9 | else 10 | { 11 | a[t]=a[t-p]; 12 | db(n,k,v,a,t+1,p); 13 | for (int i=a[t-p]+1; i de_bruijn(int n,int k) 21 | { 22 | vector v; 23 | int a[n*k]; 24 | memset(a,0,sizeof(a)); 25 | db(n,k,v,a); 26 | return v; 27 | } 28 | -------------------------------------------------------------------------------- /模板/9_数学/9_De_Bruijn序列.tex: -------------------------------------------------------------------------------- 1 | $k$为元素值范围,$n$为串长度。 -------------------------------------------------------------------------------- /模板/现场赛宝典.tex: -------------------------------------------------------------------------------- 1 | \section{现场赛宝典} 2 | 1、比赛前晚一定要睡眠充足,至少保证8-10个小时睡眠时间。 \\ 3 | 2、热身赛不要纠结AK什么的,保证A掉一题就可以了。其他时间测试下编译器打表(多长能编译通过)、内存空间、快捷键等等。 \\ 4 | 3、热身赛每个人都轮流适应一下比赛机器。同时测试一下打印代码的流程,和提问、提交流程。要求每个队员都熟悉流程,保证提交不会出现错误。 \\ 5 | 4、热身赛后及时调节心情,如果一定要想出这道题怎么做,要果断问身边的大牛,没有疑惑和纠结度过周六。 \\ 6 | 5、赛前的心情非常非常重要!队友之间一定要互相开玩笑,保持愉快的心情开场。实在所有人都没有心情娱乐,那就脸部保持微笑状态三分钟,保证能改变心情。(强颜欢笑也是乐) \\ 7 | 6、开场后分配好题目(一般前中后三部分),英语好要迅速读完题目,并且指定一个人每两三分钟看一次rank,保证FB后迅速换题) \\ 8 | 7、如果读题过程中能确定某题可出,并且为队友的擅长题型,迅速通知队友,并说清题意、题目条件,讨论是否可敲。如果敲题,这时候读完自己题目后,还继续把队友没读的题读完。 \\ 9 | 8、看到有人出题后一定要第一时间阅读该题,有条件最好两人同时读,并且保证题目描述、条件和输入输出都没有异议。讨论该题的可行性,如果完全没有思路,并且是神校出题,再观望一段时间,别盲目敲题。 \\ 10 | 9、一定一定要记住!比赛有五个小时,开场一定要淡定,保证好首次提交,很影响士气。两人仔细检查输入输出范围,多跑几遍样例,保证多case考虑了,保证输出格式、没多余空格、空行。可能的trick还有提交流程。 \\ 11 | 10、提交后有一段等待时间,这时候不要全部盯着屏幕等,不管对错,直接打印代码,然后再检查一遍输入输出和数据,检查代码有没有问题。空闲的人继续读题或看榜。 \\ 12 | 11、如果提交没过,有其他题在开着,换人敲。之前的人拿着打印的代码检查bug。如不能保证bug很快找到,至少两个人同时debug,不需要双开。 \\ 13 | 12、如果某题2次WA,并且找不到原因,这时候一边debug一边让别人重新读一遍题目,逐字分析条件和输入输出,不受其他人影响,然后交流题意等等是否出现问题。题意和算法没问题的情况下,想trick出数据。 \\ 14 | 13、YES了一道题后,主敲队员最好的放松方法就是去趟洗手间!不管想不想方便,去洗个脸,呼吸一下新鲜空气也是很有必要的。清醒一下,把YES的那道题抛到脑后,关注其他题。还有就是在脑子非常乱的时候,非常憋屈的时候,也去趟洗手间,说不定还能偷瞄到大神的思路…… \\ 15 | 14、比赛士气和心情很重要,一定要有一个队员心理素质够硬,负责调动全队状态。小口喝水、身体坐正,双手交叉,互相打气能快速帮你调整状态。 \\ 16 | 15、比赛期间以观察rank为出题标准,但是如果认定该题不适合你们,要果断先选择另外一道过的人较多的题! \\ 17 | 16、在没有两个人都足够主敲的情况下,切忌双开敲题,尤其到了最后一两个小时,一般三人全力攻题!出题的同时,空闲队员想好trick数据等等。 \\ 18 | 17、封榜后一定不能乱,不要盲目交题,不要重复交同样代码!!参考11、12 \\ 19 | 18、记得比赛比的是心态和状态,如果浮躁,自己就先输了,一定要淡定!如果开始自己或队友发现出现浮躁慌乱,一定要提醒大家,参考13、14 \\ 20 | 19、相信自己,相信队友,和谐相处,共同拿牌!!! \\ 21 | 20、欢迎补充~~ \\ 22 | --------------------------------------------------------------------------------