Jeanny
寂兮,寥兮,独立不改,周行而不殆

https://oi-wiki.org/lang/csl/associative-container/
1.基本操作
2.自定义比较方式
P5250 【深基17.例5】木材仓库 set/ multiset

#include<iostream>
#include<set>
using namespace std;
int t, x, y;
set<int> s;  //由于不重复放置,这里写成multiset也可以
int main(){
    scanf("%d",&t);
    for(int i = 1; i <= t; i++){
        scanf("%d%d",&x,&y);
        if(x == 1){
            if(s.find(y) != s.end()) printf("Already Exist\n");
            else s.insert(y);
        }else{
            if(s.empty()){
                printf("Empty\n");continue;
            }
            set<int>::iterator it, ip;
            it = ip = s.lower_bound(y);
            if(it == s.begin()){
                printf("%d\n",*it); s.erase(it); //所有的erase都少了*
            }
            else if(it == s.end()){
                printf("%d\n",*(--it)); s.erase(it);
            }
            else if(y - (*(--it)) <= (*ip) - y){
                printf("%d\n",*it); s.erase(it);
            }
            else{
                printf("%d\n",*ip); s.erase(ip);
            }
        }
    }
    return 0;
}
/*
13
1 5
1 5
1 5
1 5
1 5
2 5
2 5
2 5
2 5
2 5
1 100000
1 1
2 5
*/

POJ 3481 Double Queue
【问题描述】
每个顾客有个编号和优先级,银行每次可以添加顾客的要求进队列,且保证队列中当
前任意顾客的编号和优先级都不同。银行可以执行先服务最大优先级的顾客或者先服务最
小优先级的顾客操作。对于每个服务,输出顾客的编号。
存在以下操作:
1 K P 增加编号为 K,优先级为 P 的顾客到等待队列中;
2 服务优先级最大的顾客,且将其从等待队列中取出;
3 服务优先级最小的顾客,且将其从等待队列中取出;
【输入格式】
每行输入一个请求,最后以输入 0 结束,输入格式如题目描述。
你可以假设,当操作为 1 时,不会同时存在相同的客户编号 K,或者相同的优先级 P。 (𝐾 ≤ 106, 𝑃 ≤ 107)同一个客户可以多次进入等待队列,以不同的优先级。
【输出格式】
对于每个 2 和 3 的请求时,输出顾客编号,如果遇到等待队列为空,输出0。
分析:

本题要求处理银行排队问题,根据每行的输入处理数据;若输入为1则继续输入两个整数,以第一个数为权值,第二个数为优先级(数值越大优先级越高)加入排队系统中;若输入为2 则处理当前优先级最高的用户,并输出用户的权值;若输入为3 则处理当前优先级最低的用户,并输出用户权值;若输入为0结束运行。若当没有排队人数则无论输入2、3都输出0。

  利用set自带红黑树排序的性质,可以在集合中直接获取最高与最低优先级,用pair记录权值和优先级,将pair传入集合。用迭代器可以获得集合首位(最大优先级)和集合末尾(最小优先级),数据处理完毕后可以通过erase()删除当前用户以便后续操作。
set 结构体.

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<cmath>
#include<set>
using namespace std;
struct Node{
    int id, pri;
    Node(){};
    Node(int x, int y):id(x),pri(y){}
    bool operator < (const Node &y) const{
        return pri > y.pri;
    }
};
set<Node> st;
int main(){
    int n,x,y;
    while(scanf("%d",&n) != EOF){
        if(n == 0) break;
        if(n == 1){
            scanf("%d%d",&x, &y);
            st.insert(Node(x,y));
            set<Node>::iterator it = st.begin();
            // cout<<"begin "<<(*it).pri<<endl;
        }
        if(n == 2){
            if(!st.empty()){
                set<Node>::iterator it = st.begin();
                printf("%d\n",(*it).id);
                st.erase(it);
            }
            else{
                printf("0\n");
            }
        }
        if(n == 3){
            if(!st.empty()){
                set<Node>::iterator it = st.end();
                it--;
                printf("%d\n",(*it).id);
                st.erase(it);
            }
            else{
                printf("0\n");
            }
        }
    };
    return 0;
}

双关键字set排序,set返回第一个关键字大的位置,第二个不一定大,如果第一个关键字和查询的一样大,则返回第二个关键字大的位置

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<set>
using namespace std;
#define INF 0x3f3f3f3f
int main()
{
  set<pair<int,int> > s;
  s.insert(make_pair(3,1));
  s.insert(make_pair(3,2));
  s.insert(make_pair(1,8));
  s.insert(make_pair(1,2));
  s.insert(make_pair(3,5));
  s.insert(make_pair(2,6));
  set<pair<int ,int> > ::iterator it;
  for(it=s.begin();it!=s.end();it++){
    cout<<it->first<<' '<<it->second<<"\n";
    cout<<(*it).first<<" "<<(*it).second<<endl;
}
  it=s.lower_bound(make_pair(3,-1));
  if(it!=s.end())
    printf("(3,-1)后面接着是%d %d\n",it->first,it->second);
}

P8686 修改数组
逆向思维,排区间的右端点

#include <iostream>
#include <set>
using namespace std;
typedef pair<int, int > PII;
const int N = 5e5 + 10;
int cnt[N];
set<PII>q;
void insert(int l, int r) {
    if (l < r) return;
    q.insert(make_pair(l, r));
}
int main() {
    int n;
    cin >> n;
    q.insert(make_pair(2e9 + 10, 1));
    for (int i = 0; i < n; i++) {
        cin >> cnt[i];
        set<PII>::iterator it;
        it = q.lower_bound(make_pair(cnt[i], 0));//error (cnt[i], cnt[i])
        if (it->second <= cnt[i]) {
            cout << cnt[i] << ' ';
            insert(cnt[i] - 1, it->second);
            insert(it->first, cnt[i] + 1);
            q.erase(it);
        }
        else {
            cout << it->second << ' ';
            insert(it->first, it->second + 1);
            q.erase(it);
        }
    }
}
/*
5  10  15
[1,4] [6,9] [11,15]

4
5 10 15 9err
*/

sdfzoj庐州月
和逆序对比较像,两个关键字,把一个关键字比自己大挑出来,对应的另一个关键字放set里,查询另一个关键字比自己大的元素

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#define ll long long
using namespace std;
int n,m,x,y; ll sum;
multiset<int> st;
multiset<int> :: iterator it;
struct Node{
    int x,y;
}a[100005], b[100005];
bool cmp(Node p, Node q){
    if(p.y == q.y) return p.x > q.x;
    return p.y > q.y;
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i = 1; i <= n; i++) scanf("%d%d",&a[i].x,&a[i].y);
    for(int i = 1; i <= m; i++) scanf("%d%d",&b[i].x,&b[i].y);
    sort(b+1, b+m+1, cmp); sort(a+1, a+n+1, cmp);
    int j = 1;
    for(int i = 1; i <= n; i++){
        for(;j <= m; j++){
            if(b[j].y >= a[i].y) st.insert(b[j].x);
            else break;
        }
        it = st.lower_bound(a[i].x);
        sum += (*it);
        st.erase(it);
    }
    cout<<sum<<endl;
    return 0;
}
/*
(2,6)(5,4)(4,4)(4,3)(5,2)(3,2)(2,1)
(1,4)(2,3)(4,2)(1,1)
*/

KLO砖块
动态维护中位数,双set

posted on 2023-05-09 21:36  Jeanny  阅读(52)  评论(0)    收藏  举报