Acwing 基础算法打卡笔记 with C++

CONTENTS

  • 第一章:基础算法:两种排序、二分、高精度、前缀和、差分、双指针
    • 内 置 的 排 序 内置的排序
    • 快 速 排 序 快速排序
    • 选 择 问 题 选择问题
      • 方法一:排序
      • 方法二:优先队列
      • 方法三: n t h _ e l e m e n t ( ) nth\_element() nth_element() ~英文翻译:第n个元素~
    • 归 并 排 序 归并排序
    • 二 分 模 板 二分模板
      • 区间划分成 [l,mid] + [mid+1,r] 时
      • 区间划分成 [l,mid-1] + [mid,r] 时
      • 实数域二分
    • 高 精 度 高精度
      • python
      • C++
    • 前 缀 和 以 及 差 分 前缀和以及差分
    • 双 指 针 双指针
        • 输出一个字符串中的全部单词(以空格隔开)
          • 法一: s p l i t split split
          • 法二:双指针
        • 最长连续不重复子序列
    • 位 运 算 位运算
        • l o w b i t lowbit lowbit
    • 离 散 化 离散化
      • 法一:离散化
      • 法二: H a s h M a p HashMap HashMap
    • 区 间 合 并 区间合并 ~贪心常用~
  • 第二章:数据结构:链表与邻接表、栈与队列、KMP


第一章:基础算法:两种排序、二分、高精度、前缀和、差分、双指针


内 置 的 排 序 内置的排序

初学算法没多久,队长就给我们讲了 S T L STL STL 中的 sort

#include 
sort(int*,int*,bool);

不知道这样写是不是不太合适 不过总而言之,sort的强大之处在于第三个参数可以自己指定排序规则…great…结构体…甚至可以自己写 l a m b d a lambda lambda e x p r e s s i o n s expressions expressions
不过我现在还不太会…先挖个坑好了…

快 速 排 序 快速排序

思想基于 DNC (分而治之)。
划分区间的时候使用双指针…(之前《啊哈!算法》也看到过…)
quick_sort

#include 
#include 
using namespace std;
const int MAX_N = 1e5 + 10;
int n,arr[MAX_N];
void quick_sort(int l,int r){
     
	if(l>=r)
		return;
	int x = arr[(l+r)>>1],i = l-1,j = r+1;
	while(i<j){
       /*两个哨兵指针*/
		do i++;while(arr[i]<x);
		do j--;while(arr[j]>x);
		if(i<j) 
			arr[i]^=arr[j]^=arr[i]^=arr[j];}
	quick_sort(l,j);
	quick_sort(j+1,r);}/*分治左右*/
int main(void){
     
scanf("%d",&n);
for(int i=0;i<n;++i)
	scanf("%d",&arr[i]);
quick_sort(0,n-1);
for(int i=0;i<n;++i)
	printf("%d ",arr[i]);
return 0;}

选 择 问 题 选择问题

选择问题,其实就是求 第k小/大的数

方法一:排序

你当然可以 先排序之后再输出这个数 ,就是下面这样:

#include 
#include 
using namespace std;
const int MAX_N = 1e5 + 10;
int n,k,arr[MAX_N];
void quick_sort(int l,int r){
     
	if(l>=r)
		return;
	int x = arr[(l+r)>>1],i = l-1,j = r+1;
	while(i<j){
     
		do i++;while(arr[i]<x);
		do j--;while(arr[j]>x);
		if(i<j)
			arr[i]^=arr[j]^=arr[i]^=arr[j];}
	quick_sort(l,j);
	quick_sort(j+1,r);}
int main(void){
     
scanf("%d%d",&n,&k);
for(int i=0;i<n;++i)
	scanf("%d",&arr[i]);
quick_sort(0,n-1);
	printf("%d",arr[k-1]);
return 0;}

方法二:优先队列

不过事实上,你也可以维护一个 k k k 这么长的区间,使用 优先队列 即可。但分析一下,当 k = n 2 k = \frac{n}{2} k=2n (也即是所求为中位数) 时,好像就没有那么好用了。不过也有优化的方法!详见 《数据结构与算法》 那本黑书吧!

#include 
#include 
#include 
using namespace std;
const int MAX_N = 1e5 + 10;
int n,k,arr[MAX_N];
int main(void){
     
priority_queue<int> q;
scanf("%d%d",&n,&k);
for(int i=0;i<n;++i)
	scanf("%d",&arr[i]);
for(int i=0;i<k;++i)
	q.push(arr[i]);
for(int i=k;i<n;++i)
	if(q.top() > arr[i]){
     
		q.pop();
		q.push(arr[i]);}
printf("%d",q.top());
return 0;}

方法三: n t h _ e l e m e n t ( ) nth\_element() nth_element() 英文翻译:第n个元素

草,这种问题…已经有官方解答了吗么…

#include 
#include 
#include 
using namespace std;
const int MAX_N = 1e5 + 10;
int n,k,arr[MAX_N];
int main(void){
     
scanf("%d%d",&n,&k);
for(int i=0;i<n;++i)
	scanf("%d",&arr[i]);
    nth_element(arr,arr+k-1,arr+n);
	printf("%d",arr[k-1]);
return 0;}

归 并 排 序 归并排序

分成两个部分 (DNC) ,分别排序,最终合二为一。
Yxc老师顺便讲到了 排序算法的稳定性 其实就是相同元素的相对顺序是否发生改变,发生改变就是不稳定的,例如 快速排序
merge sort

#include 
#include 
using namespace std;
const int MAX_N = 1e5 + 10;
int n,k,arr[MAX_N],tmp[MAX_N];
void merge_sort(int l,int r){
     
	if(l>=r)
		return;
	int mid = (l+r)>>1;
	merge_sort(l,mid);
	merge_sort(mid+1,r);/*分治左右*/
	int k = 0,i = l,j = mid+1;
	while(i<=mid && j<=r)
		if(arr[i]<=arr[j])
			tmp[k++] = arr[i++];
		else
			tmp[k++] = arr[j++];
	while(i<=mid)
		tmp[k++] = arr[i++];
	while(j<=r)
		tmp[k++] = arr[j++];
	for(int i=l,j=0;i<=r;++i,++j)
		arr[i] =  tmp[j];}/*归并(合二为一)*/
int main(void){
     
scanf("%d",&n);
for(int i=0;i<n;++i)
	scanf("%d",&arr[i]);
	merge_sort(0,n-1);
for(int i=0;i<n;++i)
    printf("%d ",arr[i]);
return 0;}

逆序对数量


二 分 模 板 二分模板

区间划分成 [l,mid] + [mid+1,r] 时

M i n m a x Minmax Minmax

int BiSL(int l,int r){
     
	while(l<r){
     
		int mid = l+r >> 1;
		if(check(mid))
			r = mid;
		else
			l = mid + 1;}
return l;}

区间划分成 [l,mid-1] + [mid,r] 时

M a x m i n Maxmin Maxmin

int BiSR(int l,int r){
     
	while(l<r){
     
		int mid = l+r+1 >> 1;
		if(!check(mid))
			r = mid - 1;
		else
			l = mid;}
return l;}

实数域二分

e p s eps eps 的值取决于题目
若要保留 n 位小数,取 1 0 − ( n + 2 ) 10^{-(n+2)} 10(n+2)

const double eps = 1e-8;
double BiSF(double l,double r){
     
	while(r-l>eps){
     
		double mid = (l+r)/2.0;
		if(check(mid))
			r = mid;
		else
			l = mid;}
return l;}

二分-数的范围

#include 
#include 
using namespace std;
const int MAX_N = 1e5+7;
int n,m,arr[MAX_N];
int main(void){
     
    scanf("%d%d",&n,&m);
    for(int i=0;i<n;++i)
        scanf("%d",&arr[i]);
    while(m--){
     
        int x;
        scanf("%d",&x);
        int l = 0,r = n-1;
        while(l<r){
     
            int mid = l+r >> 1;
            if(arr[mid]>=x)
                r = mid;
            else
                l = mid+1;}
    if(arr[l]!=x)
        printf("-1 -1\n");
    else{
     
        printf("%d ",l);
        int l = 0,r = n-1;
        while(l<r){
     
            int mid = l+r+1 >> 1;
            if(!(arr[mid]<=x))
                r = mid-1;
            else
                l = mid;}
        printf("%d\n",l);}}
return 0;}

实数域二分-数的三次方根

#include 
#include 
using namespace std;
const double eps = 1e-8;
int main(void){
     
    double x;    
    scanf("%lf",&x);
    double l = -100.0,r = 100.0;
    while(r-l>eps){
     
        double mid = (l+r)/2.0;
        if(mid*mid*mid>=x)
            r = mid;
        else
            l = mid;}
    printf("%.6lf",l);
return 0;}

高 精 度 高精度

加 减 乘 除

python

毕竟 python 没有数据长度限制嘛

print(int(input() + int(input())))

print(int(input() - int(input())))

print(int(input() * int(input())))

a = int(input())
b = int(input())
print(a / b)
print(a % b)

C++

1.考虑到方便进位,倒序存放(否则会增加移动的花费)
2.如果最高位进位,,记得位数加一
下面这个是之前写的…

#include 
using namespace std;
const int MAX_N = 1000010;
int main(void){
     
string a,b;
int left[MAX_N],right[MAX_N],ans[MAX_N];
cin >> a >> b;
int i,len,lena = a.length(),lenb = b.length();
for(i=0;i<lena;++i)
	left[lena-i]  = a[i] - '0';
for(i=0;i<lenb;++i)
	right[lenb-i] = b[i] - '0';
len = max(lena,lenb);
for(i=1;i<=len;++i){
     
	ans[i] += left[i] + right[i];
	ans[i+1] = ans[i]/10;
	ans[i] %= 10;}
if(ans[len+1]>0)
	++len;
for(i=len;i>0;i--)
	cout << ans[i];
return 0;}

加一点细节大概就是这样…

#include 
#include 
#include 
using namespace std;
vector<int> add(vector<int> &A,vector<int> &B){
     
    if(A.size()<B.size())
        return add(B,A);
    vector<int> C;
    int ans = 0;
    for(int i=0;i<A.size();++i){
     
        ans += A[i];
        if(i<B.size())
            ans += B[i];
        C.push_back(ans%10);
        ans/=10;}
    if(ans)
        C.push_back(ans);
return C;}
int main(void){
     
    string a,b;
    vector<int> A,B;
    cin >> a >> b;
    for(int i=a.length()-1;i>=0;--i)
            A.push_back(a[i]-'0');
    for(int i=b.length()-1;i>=0;--i)
            B.push_back(b[i]-'0');
    auto C = add(A,B);
    for(int i=C.size()-1;i>=0;--i)
        printf("%d",C[i]);
return 0;}

1.注意判断两个数字的大小
2.除去前导零

#include 
#include 
#include 
using namespace std;
bool cmp(vector<int> &A,vector<int> &B){
     
    if(A.size()!=B.size())
        return A.size() > B.size();
    for(int i=A.size()-1;i>=0;--i)
        if(A[i]!=B[i])
            return A[i] > B[i];
return true;}
vector<int> sub(vector<int> &A,vector<int> &B){
     
    vector<int> C;
    for(int i=0,t=0;i<A.size();++i){
     
        t = A[i] - t;
        if(i<B.size())
            t -= B[i];
        C.push_back((t+10)%10);
        t =(t<0)?1:0;}
    while(C.size()>1&&!C.back())
        C.pop_back();
return C;}
int main(void){
     
    string a,b;
    vector<int> A,B;
    cin >> a >> b;
    for(int i=a.length()-1;i>=0;--i)
        A.push_back(a[i]-'0');
    for(int i=b.length()-1;i>=0;--i)
        B.push_back(b[i]-'0');
    vector<int> C;
    if(cmp(A,B))
        C = sub(A,B);
    else
        C = sub(B,A),cout << "-";
    for(int i=C.size()-1;i>=0;--i)
        printf("%d",C[i]);
return 0;}

#include 
#include 
#include 
using namespace std;
vector<int> mul(vector<int>&A,int b){
     
    vector<int> C;
    int t = 0;
    for(int i=0;i<A.size()||t;++i){
     
        if(i<A.size())
            t += A[i]*b;
        C.push_back(t%10);
        t/=10;}
    while(C.size()>1&&!C.back())
        C.pop_back();
return C;}
int main(void){
     
    string a;
    int b;
    vector<int> A;
    cin >> a >> b;
    for(int i=a.length()-1;i>=0;--i)
            A.push_back(a[i]-'0');
    auto C = mul(A,b);
    for(int i=C.size()-1;i>=0;--i)
        printf("%d",C[i]);
return 0;}

#include 
#include 
#include 
#include 
using namespace std;
vector<int> div(vector<int>&A,int b,int&r){
     
    vector<int> C;
    r = 0;
    for(int i=A.size()-1;i>=0;--i){
     
        r = r*10 + A[i];
        C.push_back(r/b);
        r%=b;}
    reverse(C.begin(),C.end());
    while(C.size()>1&&!C.back())
        C.pop_back();
return C;}
int main(void){
     
    string a;
    int b,r;
    vector<int> A;
    cin >> a >> b;
    for(int i=a.length()-1;i>=0;--i)
        A.push_back(a[i]-'0');
    auto C = div(A,b,r);
    for(int i=C.size()-1;i>=0;--i)
        printf("%d",C[i]);
    printf("\n%d",r);
return 0;}

前 缀 和 以 及 差 分 前缀和以及差分

  • 简单来说,前缀和就是 数列的前 n 项和 ,因此求前缀和其实也就是给出 a n a_n an ∑ i = 1 n a i \sum_{i=1}^n a_i i=1nai 也即 S n S_n Sn 的过程。

S n = a n + S n − 1 S_n = a_n + S_{n-1} Sn=an+Sn1 事实上,初学递归的时候我还见到过不少这样的练习题…

  • 至于差分,在高中阶段我们其实学过数列的差分性质 a n = S n − S n − 1 a_n = S_n - S_{n-1} an=SnSn1
    同时不难观察出前缀和与差分是一组互逆运算
  • 前缀和这个工具的优势其实在于 O ( n ) \Omicron (n) O(n) 建立, O ( 1 ) \Omicron (1) O(1) 查找/修改,下面来看两个简单而又典型的例子来理解 查询 以及 修改
    1.查询
    不难看出上述公式 1 是一个递推式,可以用来生成前缀和数组,显然是 O ( n ) \Omicron(n) O(n) 的。而当你需要查询一段 a n a_n an 的和时,可以转化为两个前缀和的差,这只需要 O ( 1 ) \Omicron(1) O(1) 的时间!区别于循环一段累加的做法,快了很多。下面可以来看看这道题: 前缀和
#include 
#include 
using namespace std;
const int MAX_N = 1e5+7;
int n,m,l,r,arr[MAX_N],S[MAX_N];
int main(void){
     
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;++i){
     
        scanf("%d",&arr[i]);
        S[i] = S[i-1] + arr[i];}
    while(m--){
     
        scanf("%d%d",&l,&r);
        printf("%d\n",S[r]-S[l-1]);}
return 0;}

2.修改
当我们需要对整个区间进行修改的时候,我们可以使用到第二个公式所用的到结构,将和式化简成单个值的修改。
例如,有一个数列 a n = { 1 , 2 , 3 , 4 , 5 , 6 , 7 } a_n = \{1,2,3,4,5,6,7\} an={ 1,2,3,4,5,6,7} 其差分数列自然是 d n = { 1 , 1 , 1 , 1 , 1 , 1 , 1 } d_n = \{1,1,1,1,1,1,1\} dn={ 1,1,1,1,1,1,1} 如果我们要对 [ 3 , 5 ) \left[3,5\right) [3,5) 加上一,也就是 a n = { 1 , 2 , 4 , 5 , 5 , 6 , 7 } a_n = \{1,2,4,5,5,6,7\} an={ 1,2,4,5,5,6,7} 差分数列就变成了 d n = { 1 , 1 , 2 , 1 , 0 , 1 , 1 } d_n = \{1,1,2,1,0,1,1\} dn={ 1,1,2,1,0,1,1} 注意到只是将 d 3 d_3 d3 d 5 d_5 d5进行了修改,左端点加 1 ,右端点减 1 。这样也将原本 O ( n ) \Omicron(n) O(n) 的修改转换成了 O ( 1 ) \Omicron(1) O(1) 。来看一道题目吧! 差分

#include 
#include 
using namespace std;
const int MAX_N = 1e6+7;
int n,m,l,r,c,arr[MAX_N],d[MAX_N];
int main(void){
     
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;++i){
     
        scanf("%d",&arr[i]);
        d[i] = arr[i] - arr[i-1];}
    while(m--){
     
        scanf("%d%d%d",&l,&r,&c);
        d[l] += c;
        d[r+1] -= c;}
    for(int i=1;i<=n;++i){
     
        d[i] += d[i-1];
        printf("%d ",d[i]);}
return 0;}

大致明白了这个思路之后,理解 二维形式 的两者也相当轻松啦!二维前缀和 实际上看作一个子矩阵即可,若要求其前缀和,等价于上一个前缀和加上三条新的边即可…但是这样并不能很好的表示出来…最终展示的经典做法事实上可以看作 容斥原理

#include 
using namespace std;
const int MAX_N = 1e4+7;
int n, m, q,s[MAX_N][MAX_N];
int main(void){
     
    scanf("%d%d%d", &n, &m, &q);
    for(int i=1;i<=n;++i)
        for(int j=1;j<=m;++j){
     
            scanf("%d", &s[i][j]);
            s[i][j] += s[i-1][j]+s[i][j-1]-s[i-1][j-1];}
    while(q--){
     
        int x1, y1, x2, y2;
        scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
        printf("%d\n",s[x2][y2]-s[x1-1][y2]-s[x2][y1-1]+s[x1-1][y1-1]);}
return 0;}

二维差分

#include 
#include 
using namespace std;
const int N = 1010;
int n, m, q;
int a[N][N], b[N][N];
void insert(int x1, int y1, int x2, int y2, int c){
     
    b[x1][y1] += c;
    b[x2 + 1][y1] -= c;
    b[x1][y2 + 1] -= c;
    b[x2 + 1][y2 + 1] += c;}
int main(){
     
    scanf("%d%d%d", &n, &m, &q);
    for (int i = 1; i <= n; i ++ )
        for (int j = 1; j <= m; j ++ ){
     
            scanf("%d", &a[i][j]);
            insert(i, j, i, j, a[i][j]);}
    while (q -- ){
     
        int x1, y1, x2, y2, c;
        cin >> x1 >> y1 >> x2 >> y2 >> c;
        insert(x1, y1, x2, y2, c);}
    for (int i = 1; i <= n; i ++ ){
     
        for (int j = 1; j <= m; j ++ ){
      
            b[i][j] += b[i - 1][j] + b[i][j - 1] - b[i - 1][j - 1];
            printf("%d ", b[i][j]);}
        puts("");}
return 0;}

之后再补上一张图来解释这些算式叭…


双 指 针 双指针

基本上都是 O ( n ) \Omicron(n) O(n) 的时间的一种算法,常见的是 扫描例如KMP啥的…

输出一个字符串中的全部单词(以空格隔开)

法一: s p l i t split split

法二:双指针
#include 
#include 
#include 
using namespace std;
int main(void){
     
	char a[1007];
	scanf("%[^\n]",a);
	int n = strlen(a);
	for(int i=0;i<n;++i){
     
		int j = i;
		while(j<n&&a[j]!=' ')
		    ++j;
  	for(int k=i;k<j;++k)
			cout << a[k];
		cout << endl;
		i = j;}
return 0;}

最长连续不重复子序列

#include 
using namespace std;
const int N = 100010;
int n;
int q[N], s[N];
int main(void){
     
    scanf("%d",&n);
    for (int i=0;i<n;++i)
        scanf("%d", &q[i]);
    int res = 0;
    for (int i=0,j=0;i<n;++i){
     
        ++s[q[i]];
        while (j<i&&s[q[i]]>1)
            --s[q[j++]];
        res = max(res,i-j+1);}
    cout << res << endl;
return 0;}


位 运 算 位运算

n>>1&i++  //求二进制的表达方式

l o w b i t lowbit lowbit

n&(-n)    //利用补码的概念易得

实际上等价于 n&(~n+1)
二进制1的个数
一下就想到了linked to leetcode

#include 
using namespace std;
#define ll long long
int hammingWeight(ll n) {
     
    int cnt = 0;
    while(n){
     
        ++cnt;
        n &= n-1;}
return cnt;}
const int MAX_N = 1e6 + 10; 
ll n,arr[MAX_N];
int main(void){
     
scanf("%lld",&n);
for(int i=0;i<n;++i){
     
    cin >> arr[i];
    arr[i] = hammingWeight(arr[i]);}
for(int i=0;i<n;++i)
    cout << arr[i] << " ";
return 0;}

离 散 化 离散化

vector<int> alls;
sort(alls.begin(),alls.end());
alls.erase(unique(alls.begin(),alls.end()),alls.end());

排序后存在单调性,二分查找即可。 u p p e r _ b o u n d ( ) upper\_bound() upper_bound()

int find(int x){
     
	int l = 0,r = alls.size()-1;
	while(l<r){
     
		int mid = l+r >> 1;
		if(alls[mid]>=x}
			r = mid;
		else
			l = mid + 1;}
return l;}

或者直接使用 S T L STL STL

auto p1 = upper_bound(a.begin(),a.end(),(PII){
     l,-INF});
auto p2 = upper_bound(a.begin(),a.end(),(PII){
     r, INF}); 
cout << p2 -> second - p1 -> second << endl;

区间和

注:本题数据范围
− 1 0 9 ≤ x ≤ 1 0 9 −10^9≤ x ≤10^9 109x109,
1 ≤ n , m ≤ 1 0 5 1 ≤n,m≤10^5 1n,m105,
− 1 0 9 ≤ l ≤ r ≤ 1 0 9 −10^9≤l≤r≤10^9 109lr109,
− 10000 ≤ c ≤ 10000 −10000≤c≤10000 10000c10000

法一:离散化

#include 
#include 
#include 
using namespace std;
typedef pair<int, int> PII;
const int N = 300010;
int n, m;
int a[N], s[N];
vector<int> alls;
vector<PII> add, query;
int find(int x){
     
    int l = 0,r = alls.size()-1;
    while (l < r){
     
        int mid = l + r >> 1;
        if (alls[mid] >= x) 
            r = mid;
        else 
            l = mid + 1;}
return l;}
int main(void){
     
    cin >> n >> m;
    for (int i = 0; i < n; i ++ ){
     
        int x, c;
        cin >> x >> c;
        add.push_back({
     x, c});
        alls.push_back(x);}
    for (int i = 0; i < m; i ++ ){
     
        int l, r;
        cin >> l >> r;
        query.push_back({
     l, r});
        alls.push_back(l);
        alls.push_back(r);}
    sort(alls.begin(), alls.end());
    alls.erase(unique(alls.begin(),alls.end()),alls.end());
    for (auto item : add){
     
        int x = find(item.first);
        a[x] += item.second;}
    for (int i = 1; i <= alls.size(); i ++ ) s[i] = s[i - 1] + a[i];
    for (auto item : query){
     
        int l = find(item.first), r = find(item.second);
        cout << s[r] - s[l - 1] << endl;}
return 0;}

法二: H a s h M a p HashMap HashMap

#include
#include
#include
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
const int N = 300010;
long long a[N],s[N];
int main(void){
     
    ios::sync_with_stdio(false);
    map<int,ll> mp;
    int n, m; cin >> n >> m;
    for(int i = 0; i < n; i ++ ){
     
        int index, val; cin >> index >> val;
        mp[index] += val;}
    vector<PII> query;
    for(int i = 0; i < m; i ++ ){
     
        int index1, index2; cin >> index1 >> index2;
        query.push_back({
     index1, index2});
        mp[index1] += 0, mp[index2] += 0;}
    int k = 1;
    map<int, int> id;
    for(auto &[index, val] : mp){
     
        id[index] = k;
        a[k] = val;
        s[k] = s[k - 1] + a[k];
        k++;}
    for(auto &[l, r] : query){
     
        l = id[l], r = id[r];
        cout << s[r] - s[l - 1] << endl;}
return 0;}
  • 关于如何实现 u n i q u e ( ) unique() unique()
vector<int>::iterator unique(vector<int> &a){
     
   int j = 0;
   for (int i = 0; i < a.size(); i ++ )
       if (!i || a[i] != a[i - 1])
           a[j++] = a[i];
return a.begin() + j;}

区 间 合 并 区间合并 贪心常用

按照区间左端点合并

#include 
#include 
#include 
#define INF 2e9
using namespace std;
typedef pair<int, int> PII;
void merge(vector<PII> &segs){
     
    vector<PII> res;
    sort(segs.begin(), segs.end());
    int st = -INF, ed = -INF;
    for (auto seg : segs)
        if (ed < seg.first){
     
            if (st != -INF) 
                res.push_back({
     st, ed});
            st = seg.first,ed = seg.second;}
        else 
            ed = max(ed, seg.second);
    if (st != -INF) 
        res.push_back({
     st, ed});
    segs = res;}
int main(void){
     
    int n;
    scanf("%d", &n);
    vector<PII> segs;
    for (int i=0;i<n;++i){
     
        int l, r;
        scanf("%d%d",&l,&r);
        segs.push_back({
     l,r});}
    merge(segs);
    cout << segs.size() << endl;
return 0;}

第二章:数据结构:链表与邻接表、栈与队列、KMP

你可能感兴趣的:(Acwing基础算法,算法,数据结构)