【有关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;
}
}