Day 1---STL及基础数据结构

一.STL

1.stl(standard template library) 包含一些常用数据结构与算法的模板的C++软件库。其包含四个组件----算法,容器,仿函数,迭代器。

2.重要容器及其用法

1.Vector

1.用来替换普通数组

2.要提前指定长度(如果长度确定)

因为vector额外内存耗尽后的重分配是有时间开销

3.离散化操作

int find(int x)
{
    return lower_bound(alls.begin(),alls.end(),x) - alls.begin(); 
}

alls.push_back(把需要用到的数值存到alls当中)

alls.sort(alls.begin(),alls.end());
alls.erase(unique(alls.begin(),alls.end()),alls.end());

通过find函数找离散化后的值

//关于sort
1.升序sort(alls.begin(),alls.end());
2.降序1 sort(alls.begin(),alls.end(),greater<int>());
3.降序2 sort(alls.begin(),alls.end()); reverse(alls.begin(),alls.end());
    

2.Stack

1.先进后出 不可遍历元素

2.

例题.A - Plug-in

#include<iostream>
#include<cstring>
#include<algorithm>
#include<stack>
using namespace std;
const int N = 200010;
char ans[N];
stack <char> st1;
int main()
{
    string str;
    cin >> str;
    for(int i = 0;i < str.size();i++)
    {
        //如果栈不空 并且 栈顶元素 与遍历到的元素 相等 意味着可以消去
        if(!st1.empty() && st1.top() == str[i]) st1.pop();
        else st1.push(str[i]);//否则进栈
    }
    int idx = 0;
    //输出栈中内容
    while(!st1.empty())
    {
        auto t = st1.top();
        st1.pop();
        ans[idx++] = t;
    }
    for(int i = idx-1;i >= 0;i--) cout << ans[i];

}

3.Queue

1.q.push()  q.pop() q.front() q.back() 

2.不可直接访问内部元素

3.优先队列

优先队列
priority_queue<int> heap; //大根堆 heap.top() 为最大值
priority_queue<int,vector<int>,greater<int>> heap; //小根堆 heap.top() 为最小值

4.时间复杂度

插入之后快速排序 O(nlogn)

例题 Heap Operations

#include<bits/stdc++.h>
using namespace std;
const int N = 1000100;
int idx;
typedef pair<int,int> PII;
/*
简单模拟题
题目描述三种操作
1.insert --- heap.push() 
2.removeMin --- heap.pop() 要注意当堆为空 需要先加一个元素 在进行pop操作
3.getMin --- heap.top() 
*/
string moving[3] = {"insert","removeMin","getMin"};
priority_queue<int,vector<int>,greater<int>> heap;
PII ans[N];
int main()
{
    int n;
    cin >> n;
    while(n--)
    {
        string op;
        int x;
        cin >> op ;
        if(op == "insert")
        {
            cin >> x;
            ans[idx++] = {0,x};
            heap.push(x);
        }
        else if(op == "removeMin")
        {
            //当堆为空却要去掉最小值
            //手动加一个0 然后pop()
            if(heap.empty())
            {
                ans[idx++] = {0,0};
                heap.push(0);
            }
            ans[idx++] = {1,-1};
            heap.pop();
        }
        else 
        {
            cin >> x;
            //当堆顶元素 小于x 则弹出
            while(!heap.empty() && heap.top() < x)
            {
                
                ans[idx++] = {1,-1};
                heap.pop();
            }
            //如果堆空 或者堆顶元素 大于 x 那么可以直接 push(x)
            if(heap.empty() || heap.top() > x)
            {
                ans[idx++] ={0,x};
                heap.push(x);
                ans[idx++] = {2,x}; 
            }
            //如果刚好堆顶元素为 x 那么不用push
            else if(heap.top() == x)
            {
                ans[idx++] = {2,x};
            }
        }

    }

    cout << idx << endl;
    for(int i = 0;i < idx;i++) 
    {
        int t = ans[i].first;
        if(t == 1) cout << moving[t] << endl;
        else cout << moving[t] << " " << ans[i].second << endl;
    }
}

例题 Potions (Hard Version)

#include<bits/stdc++.h>
using namespace std;

typedef long long LL;
priority_queue<int,vector<int>,greater<int>> heap;
int ans;
//遇到正数直接吃
//负数先吃下去 然后放在小根堆当中
//如果这一次吃下去 变成负数了 那么将之前吃过的最小的那个负数 吐出来
int main()
{
    int n;
    cin >> n;
    LL hp = 0;
    for(int i = 0;i < n;i++)
    {
        int x;
        cin >> x;
        hp += (LL)x;
        ans ++;
        if(x < 0) heap.push(x);
        if(hp < 0)
        {
            hp -= (LL)heap.top();
            ans --;
            heap.pop();
        }
    }

    cout << ans << endl;

}

4.Map

1.遍历方式

for(auto item : mp)
{
    cout << item.first << " " << item.second << endl;
}

for(auto [key,val] : mp)
{
    cout << key << " " << val << endl;
}

2.mp.count() 判断元素是否存在

3.统计字符串出现个数

例题 Knitpicking

#include<bits/stdc++.h>
using namespace std;

const int N = 1010;

//存储不同袜子的三种状态:left right any
/*
1.把所有袜子的max(left,right)拿完
2.再每个只有any的袜子拿一个(如果拿完之后发现全部袜子拿过了 意味着 没有袜子能匹配)
3.之后拿的一个 一定能跟之前凑成一对
*/
map<string,array<int,3>> socks;

int n,sum;
//sum 用来记录袜子总数
int main()
{
    cin >> n;
    for(int i = 0;i < n;i++)
    {
        string color,type;
        int cnt;
        cin >> color >> type >> cnt;
        sum += cnt;
        if(type == "left") socks[color][0] += cnt;
        else if(type == "right") socks[color][1] += cnt;
        else socks[color][2] += cnt;
    }
    int ans = 0;
    for(auto item : socks)
    {
        string a = item.first;
        int l = socks[a][0];
        int r = socks[a][1];
        //如果袜子只有 状态 any 那么ans ++
        if(l == 0 && r == 0 && socks[a][2] > 0) ans ++;
        //如果袜子有左或者右或者都有 那么取最多的一边
        else ans += max(l,r);
    }
    //如果ans == sum 也就意味着所有袜子都选完了还没有匹配 那么返回无解
    //否则一定能再找到一只袜子 与之前选过的匹配 于是袜子数再加1
    if(ans != sum)
    {
        ans ++;
        cout << ans << endl;
    }
    else cout << "impossible";
    
}

5.Set

1。提供对数时间的插入删除查找 st.insert()  st.erase()  set.find()  st.count() (均为O(logn))

2.每个元素再set当中只出现一次 并且按照升序或者降序排列 (无下标)

set<int> st1; 从小到大
set<int,greater<int>> st2;从大到小

例题 Cutting Woods

#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> PII;
/*
    初始元素只有0 和 L 
    每次将截断位置x插入set当中
    查询位置x 只需将离x最近的左右俩边相减 就是对应的长度(题目保证 查询位置一定没有被砍)
*/
set<int> alls;

int main()
{
    int L,Q;
    cin >> L >> Q;
    alls.insert(L);
    alls.insert(0);
    while(Q--)
    {
        int op,x;
        cin >> op >> x;
        if(op == 1) alls.insert(x);
        else 
        {
            auto r = alls.lower_bound(x);
            
            cout << (*r) - *(--r) << endl;
        }
    }
}

6.String

1.基本操作

注意事项

1.string 的 += 会在原字符串尾巴直接接上 而 s = s + 'a',会生成一个临时变量 再复制给string 在字符串长度很长的时候会TLE

2.str.substr(子串起点下标,子串长度)

3.find() 时间复杂度为O(n^2)

综合题 Social Media

#include<bits/stdc++.h>

/*
    思考答案来源:1.俩个新朋友没有发过消息
                 2.俩个发过消息的新朋友
    记录 用户a ---- 用户 b
    1.当其中一个已经是朋友 则另一个的价值加一
    2.俩个都不是朋友 计算 若选择这俩人 价值总和是多少
    3.俩个已经都是朋友 ans++;
    4.单个价值当中 寻找价值最高前俩名(注意讨论只有1人的情况)
*/

using namespace std;
const int N = 200010;
bool fri[N];
void solve()
{
    memset(fri,0,sizeof fri);
    int n,m,k;
    cin >> n >> m >> k;
    vector<int> val(k + 1);//存放只选择当前人的价值
    map<pair<int,int>,int> cnt;//存放互相发过消息的俩人价值
    for(int i = 0;i < n;i++)
    {
        int c;
        cin >> c;
        fri[c] = true;
    }
    int res1 = 0;
    int res2 = 0;
    for(int i = 0;i < m;i++)
    {
        int a,b;
        cin >> a >> b;
        if(fri[a] && fri[b]) res1 ++;//俩人已经是朋友
        else if(fri[a]) val[b] ++;
        else if(fri[b]) val[a] ++;
        else//俩人都不是朋友
        {
            if(a > b) swap(a,b);
            if(a == b) val[a] ++;
            else
            {
                cnt[{a,b}] ++;
            }
        }
    }
    for(auto [p,c] : cnt)
    {
        auto [a,b] = p;
        res2 = max(val[a] + val[b] + c,res2);
    }
    vector<int> tmp;
    for(int i = 1;i <= k;i++)
    {
        if(!fri[i])
        {
            tmp.push_back(val[i]);
        }
    }
    sort(tmp.begin(),tmp.end(),greater<int>());
    if(tmp.size() >= 2)
    {
        res2 = max(res2,tmp[0] + tmp[1]);
    }
    else if(tmp.size() == 1) res2 = max(res2,tmp[0]);

    cout << res1 + res2 << endl;
}

int main()
{
    int T;
    cin >> T;
    while(T--)
    {
        solve();
    }
    return 0;
}

7.ST表 (RMQ)

st表就是通过一种倍增的思想可以多而不可以少的覆盖一段区间
也就是需要满足自身和自身操作不会有变化的时候可以使用st表

例题 acwing1273. 天才的记忆

#include<iostream>
#include<algorithm>
#include<cmath>

using namespace std;

const int N = 200010,M = 18;

int w[N];
int f[N][M];
int n,m;

void init()
{
    for(int j = 0;j < M;j++)
    {
        for(int i = 1;i + (1 << j) - 1 <= n;i++)
        {
            if(!j) f[i][j] = w[i];
            else f[i][j] = max(f[i][j-1],f[i + (1 << j - 1)][j - 1]);
        }
    }
}

int quiry(int l,int r)
{
    int len = r - l + 1;
    int k = log(len)/log(2);
    
    return max(f[l][k],f[r - (1 << k) + 1][k]);
}


int main()
{
    
    cin >> n;
    for(int i = 1;i <= n;i++) cin >> w[i];
    init();
    cin >> m;
    while(m--)
    {
        int l,r;
        cin >> l >> r;
        cout << quiry(l,r) << endl;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值