题目的意思是在[1,n]区间中执行两种操作:
操作一:给定区间[l,r],依次标记该区间的所有数,如果数字已经在之前的被标记了,则不重复标记
操作二:给定[1,n]中的一个数x,直接输出x是第几个被标记的;如果没有被标记过,直接输出0
显然最直接的操作是遍历[l,r]依次标记,但是肯定会超时。
原因在于将所有数都进行判断:如果没有被标记过,那么我就标记;如果被被标记过,我就跳过
如果能不再判断被标记过的数,而是直接依次标记[l,r]中没有被标记过的数,那么不会超时,因为每个数最多标记一次,所以总共的标记次数为n次
那么我们可以用set来模拟
set<int> se
*se.lower_bound(x)直接查找第一个大于等于x的数.
int l, r; cin >> l >> r;
int now = l;
while(1){
int next = *se.lower_bound(now);
if(next > r) break;
else ans[next] = ++ idx, se.erase(next);
now = next;
}
不断标记[l,r]中未被标记过的数,并且不断删除刚才被标记的数(所以set里面的数全是没有被标记过的数,标记数字和删除被标记的数字同时发生)
总代码:
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
#define int long long
#define IOS ios::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
#define HelloWorld IOS;
signed main(){
HelloWorld;
int n, q; cin >> n >> q;
set<int> se;
for(int i = 1; i <= n + 1; i ++) se.insert(i);
vector<int> ans(n + 10);
int idx = 0;
while(q --){
int op; cin >> op;
if(op == 1){
int l, r; cin >> l >> r;
int now = l;
while(1){
int next = *se.lower_bound(now);
if(next > r) break;
else ans[next] = ++ idx, se.erase(next);
now = next;
}
}
else{
int x; cin >> x;
cout << ans[x] << endl;
}
}
return 0;
}



京公网安备 11010502036488号