【有关STL的模拟】

【有关STL的模拟】

STL很多都具有 O(logn) 的复杂度
可以处理很多 看起来要用数据结构的题

众数

https://ac.nowcoder.com/acm/contest/111309/D

分析

看题目n<=1e3->可以n^2遍历
要求每次修改后查找最大值是O(logn),修改也要O(logn)
->线段树?如果每次只是修改两个点再修改回来,并找最大值->set<PII>

代码

int n;
set<PII> t;
map<int,int> q;
//删除和插入操作函数可以单独写
void add(int x){
    if(q[x]>0) t.erase({q[x],x});//记得特判:加入新数/原先数为0要删去
    q[x]++;
    t.insert({q[x],x});
}
void sub(int x){
    t.erase({q[x],x});
    q[x]--;
    if(q[x]>0)t.insert({q[x],x});
}
bool cmp(int x,int y){
    return x<y;
}
void solve(){
    cin>>n;
    vector<int> a(n+1,0);
    for(int i=1;i<=n;i++){
        cin>>a[i];
        q[a[i]]++;
    }
    for(int i=1;i<=n;i++){
        t.insert({q[a[i]],a[i]});
    }
    map<int,int> ans;
    for(int i=1;i<=n;i++){
        sub(a[i]);add(a[i]+1);
        for(int j=1;j<=n;j++){
            if(i==j) continue;
            sub(a[j]);add(a[j]-1);
            ans[(t.rbegin())->second]=1;//注意写法
            sub(a[j]-1);add(a[j]);
        }
        sub(a[i]+1);add(a[i]);
    }
    vector<int> anss;
    for(auto [key,val]:ans){
        anss.push_back(key);
    }
    sort(anss.begin(),anss.end(),cmp);
    for(auto son:anss){
        cout<<son<<" ";
    }
    cout<<endl;
}

Changing the String

https://codeforces.com/contest/2111/problem/E
基于贪心的模拟
用set可压到O(nlogn)的复杂度

const int N=4;
/*思路没问题 实现比较有问题
【贪心】
只考虑5种变换:
b->a
b->c->a
c->a
c->b->a
c->b
字典序有先后->遍历一遍字符串即可
注意两次变换b->c->a/c->b->a是有次序的!注意前后次序->set维护+查找 可以达到nlogn
*/
int n,q;
string s;
set<int> g[N][N];
void solve(){
    cin>>n>>q;
    cin>>s;
    for(int i=0;i<3;i++){
        for(int j=0;j<3;j++) g[i][j].clear();
    }
    for(int i=1;i<=q;i++){
        char x,y;
        cin>>x>>y;
        int xx=x-'a',yy=y-'a';
        g[xx][yy].insert(i);
    }
    for(int i=0;i<n;i++){
        if(s[i]=='b'){
            //b->a
            if(g[1][0].size()){
                s[i]='a';
                g[1][0].erase(*g[1][0].begin());//注意这里优先选择靠前的操作
                continue;
            }
            if(g[1][2].size() && g[2][0].size()){
                auto pos1=*g[1][2].begin();
                auto pos2=g[2][0].lower_bound(pos1);
                if(pos2!=g[2][0].end()){
                    s[i]='a';
                    g[1][2].erase(pos1);
                    g[2][0].erase(pos2);
                    continue;
                }
            }
        }
        if(s[i]=='c'){
            if(g[2][0].size()){
                s[i]='a';
                g[2][0].erase(*g[2][0].begin());
                continue;
            }
            if(g[2][1].size() && g[1][0].size()){
                auto pos1=*g[2][1].begin();
                auto pos2=g[1][0].lower_bound(pos1);
                if(pos2!=g[1][0].end()){
                    s[i]='a';
                    g[2][1].erase(pos1);
                    g[1][0].erase(pos2);
                    continue;
                }
            }
            if(g[2][1].size()){
                s[i]='b';
                g[2][1].erase(*g[2][1].begin());
                continue;
            }
        }
    }
    cout<<s<<endl;
}

小红的区间修改(一)

【区间问题】
https://ac.nowcoder.com/acm/contest/111159/D
map可作为对key升序的[key,value]键值对进行存储
可用lower_bound/upper_bound进行二分查找
可用begin(),end()找最大最小 (可以特殊记一般不用)

int q;
/*
【利用map单调性】
插入区间 O(1)
查找区间是否已经有被覆盖的 O(logn)
*/
map<int,int> b;
void solve(){
    cin>>q;
    int ans=0;
    int rmax=0;
    while(q--){
        int l,r;
        cin>>l>>r;
        auto pos=b.lower_bound(l);
        int len=r-l+1;
        //没有大于等于l的区间左端点:还需要考虑最后一个的右端点(除非为空)
        if(pos==b.end()){
            if(b.empty()){
                ans=max(ans,len);
                cout<<ans+1<<endl;
                b[l]=r;
                rmax=max(r,rmax);
                continue;
            }
            if(rmax<l){
                ans=max(ans,len);
                cout<<ans+1<<endl;
                b[l]=r;
                rmax=max(r,rmax);
                continue;
            }
        }
        //大于等于l区间左端点同时大于r
        if(r<pos->first){
            //如果是第一个区间一定不会覆盖
            if(pos==b.begin()){
                ans=max(ans,len);
                cout<<ans+1<<endl;
                b[l]=r;
                rmax=max(r,rmax);
                continue;
            }
            //上一个区间右端点小于l
            if((--pos)->second<l){
                ans=max(ans,len);
                cout<<ans+1<<endl;
                b[l]=r;
                rmax=max(r,rmax);
                continue;
            }
        }
        //被操作后插入
        cout<<ans+1<<endl;
    }
}
posted @ 2025-05-30 23:36  White_ink  阅读(4)  评论(0)    收藏  举报