线段树思路:
- 要找结束时间小于当前物品开始时间的机器,线段树上维护区间最小值
- 要找早出现的可行位置,线段树上二分,查询返回尽可能靠左的位置,i-n没有的话1-i再查
- 找到位置要单点更新
点击查看代码
#include <iostream>
#include <map>
#include <vector>
#include <algorithm>
#include <stack>
#include <cstdio>
#include <queue>
#include <set>
#include<sstream>
#include <cstring>
#include <cmath>
#include <bitset>
//#pragma GCC optimize(2);
#define IOS ios::sync_with_stdio(false);
#define mm(a, b) memset(a, b, sizeof(a))
#define il segtree[i].l
#define ir segtree[i].r
#define jl segtree[j].l
#define jr segtree[j].r
const double PI = acos(-1.0);
typedef long long ll;
const int N = 1e5+5;
const int M = N*2;
const double eps =1e-8;
const ll mod = 998244353;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const double maxd = -1e9;
const int maxn = 500;
using namespace std;
typedef pair<string,int> PII;
struct SegTree{
int val;
}segtree[N<<2];
void push_up(int rt){
segtree[rt].val = min(segtree[rt<<1].val,segtree[rt<<1|1].val);
}
void build(int l,int r,int rt){
if(l == r) { segtree[rt].val = 0; return ; }
int mid =l+r>>1;
build(l,mid,rt<<1); build(mid+1,r,rt<<1|1);
push_up(rt);
}
int query(int a,int b,int val,int l,int r,int rt){
if(l==r&&val>=segtree[rt].val){ return l; }
int mid = l+r>>1;
int ans = -1;
if(a<=mid&&val>=segtree[rt].val) ans = query(a,b,val,l,mid,rt<<1);//选的位置尽可能靠左
if(b>mid&&val>=segtree[rt].val&&ans == -1) ans = query(a,b,val,mid+1,r,rt<<1|1);
return ans;
}
void modify(int pos,int val,int l,int r,int rt){
if(l == r) { segtree[rt].val = val; return; }
int mid =l+r>>1;
if(pos<=mid) modify(pos,val,l,mid,rt<<1);
else modify(pos,val,mid+1,r,rt<<1|1);
push_up(rt);
}
int cnt[N];
int main(){
int n,m,a,b;
cin>>n>>m;
build(1,n,1);
int maxx = 0;
for(int i=1;i<=m;i++){//全部向右偏移一位
cin>>a>>b;
int u = i%n;
if(!u) u = n;
int t = query(u,n,a,1,n,1);
if(t!=-1) cnt[t-1]++;
else{
t = query(1,u,a,1,n,1);
if(t == -1) continue;
cnt[t-1]++;
}
modify(t,a+b,1,n,1);
maxx =max(cnt[t-1],maxx);
}
vector<int>ans;
for(int i=0;i<n;i++)
if(cnt[i] == maxx) ans.push_back(i);
for(int i=0;i<ans.size();i++){
if(i)printf(" ");
printf("%d",ans[i]);
}
return 0;
}
STL思路:
- 一个堆u放k个机器的编号和它的结束时间
- 另一个放当前物品能上的机器的编号v
- 在v上二分找编号
- 注意物品的起始时间是非递减的
- 重载小于号时候time相等必须排id
点击查看代码
#include <iostream>
#include <map>
#include <vector>
#include <algorithm>
#include <stack>
#include <cstdio>
#include <queue>
#include <set>
#include<sstream>
#include <cstring>
#include <cmath>
#include <bitset>
//#pragma GCC optimize(2);
#define IOS ios::sync_with_stdio(false);
#define mm(a, b) memset(a, b, sizeof(a))
const double PI = acos(-1.0);
typedef long long ll;
const int N = 1e5+5;
const int M = N*2;
const double eps =1e-8;
const ll mod = 998244353;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const double maxd = -1e9;
const int maxn = 500;
using namespace std;
typedef pair<string,int> PII;
int a[N],b[N];
struct node{
int id, val;
bool operator< (const node b)const {
if(val == b.val) return id<b.id;
return val<b.val;
}
};
set<node>u;
set<int> v; int cnt[N]; int maxx;
int main(){
int k,n;
cin>>k>>n;
for(int i=0;i<n;i++)cin>>a[i]>>b[i];
for(int i=0;i<min(n,k);i++){
cnt[i]++;maxx =max(maxx,cnt[i]);
u.insert({i,a[i]+b[i]});
}
for(int i = k; i <n;i++){
while(!u.empty()){
node top = *u.begin();
if(top.val<=a[i]) v.insert(top.id),u.erase(u.begin());
else break;
}
if(v.empty())continue;
int d = i%k;
auto it = v.lower_bound(d);
if(it == v.end()) it =v.begin();
cnt[*it]++;
maxx =max(maxx,cnt[*it]);
u.insert({*it,a[i]+b[i]});
v.erase(it);
}
vector<int>ans;
for(int i=0;i<k;i++)
if(cnt[i] == maxx) ans.push_back(i);
for(int i=0;i<ans.size();i++){
if(i)printf(" ");
printf("%d",ans[i]);
}
return 0;
}