奇怪的自助餐厅--扫描线
问题描述
有一家奇怪的预约式自助餐厅,这家餐厅按时间计费,每一单位时间都会收取价格,不同桌位有不同价格,每个桌位从1编号到n,并且当单位时间内餐厅人数大于一定值时每个桌位这个单位时间的价格都会翻倍。
来这个餐厅吃饭的也是一些奇怪的人,他们都会提前预约一个时段,一般情况下会在时段结束后才离开,有时在一个时间单位开头会发生突发事件,编号在l-r区间内的桌位的客人突然有急事离开,为了照顾这些客人,餐厅不收取他们之后的预约时间单位的钱。预约时段在突发事件开始的客人与突发事件无关。
现在给出m个预约,c个突发事件,你需要计算餐厅的收入是多少。
输入
第一行3个整数n, m, k,分别代表餐厅的桌位数,预约个数以及餐厅在人数大于k时价格翻倍,之后一行输出n个整数,第i个整数xi代表第i个桌位每个单位时间的价格,之后输出m行,每一行三个整数l, r, x,代表一个预约从l时间到r时间(闭区间),坐在x桌位,保证没有两个人同一时间预约同一个桌位。
之后一个整数c,代表突发事件个数,之后c行,每行三个整数y, cl, cr代表事件发生在y时间开头,受影响桌位区间是cl, cr,因为这个事件离开的人不需要支付y时间及以后的费用。
1<=n, m, k, c<=100000,
1<=xi<=100000,
1<=l<=r<=100000,
1<=x<=n,
1<=y<=100000,
1<=cl<=cr<=n.
输出
输出一个整数表示餐厅收入。
样例输入
3 3 1
5 8 12
3 8 1
2 5 2
4 7 3
1
4 2 3
样例输出
175
思路,使用扫描线的思路。
对应的,把预约的开始、预约的结束、突发事件,都作为一类事件,对这三类事件进行不同的方式处理
以事件先后为优先级,如果事件相等,就以 1.突发事件 2.预约的结束3.预约的开始、为顺序进行优先级排序
然后再以扫描线的思路进行计算
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<set>
using namespace std;
const int MAXN = 1111;
typedef long long ll;
struct node{
//事件,座位号,类型
int time,pos,type;
node(){};
node(int time,int pos,int type):time(time),pos(pos),type(type){};
bool operator<(const node &b){
if(this->time==b.time) return this->type<b.type;
return this->time<b.time;
}
};
int ql[MAXN],qr[MAXN];
node nodes[MAXN*4];
int ssiue[MAXN];
int N,M,K,C;
int co[MAXN];
int main(){
set<int> se;
se.clear();
scanf("%d%d%d",&N,&M,&K);
for(int i=1;i<=N;i++){
scanf("%d",&co[i]);
}
int kk = 0;
for(int i=1;i<=M;i++){
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
//事件1 人预约
nodes[++kk] = node(a,c,1);
//事件2 预约结尾时间
nodes[++kk] = node(b+1,c,0);
}
scanf("%d",&C);
for(int i=1;i<=C;i++){
int a;
//事件3 突发事件
scanf("%d%d%d",&a,&ql[i],&qr[i]);
nodes[++kk] = node(a,i,-1);
}
sort(nodes+1,nodes+kk+1);
int sum = 0;
int now = 0;
ll ans = 0;
int now_num =0;
for(int i=1;i<=kk;i++){
if(now_num>K) ans += sum*(nodes[i].time - now)*2;
else ans+=sum*(nodes[i].time - now);
now = nodes[i].time;
//事件3 突发事件
if(nodes[i].type == -1){
int id = nodes[i].pos;
set<int>::iterator it= se.lower_bound(ql[id]);
while(it!=se.end() && *it<=qr[id]){
// printf("%d",*it);
ssiue[(*it)] = 0;
sum -= co[(*it)];
now_num --;
se.erase(it++);
}
//这样使用错误
// for(;it!=se.end() && *it<=qr[id];it++){
// printf("%d",*it);
// ssiue[(*it)] = 0;
// sum -= co[(*it)];
// now_num --;
// se.erase(it);
// }
}
//事件1 人预约
else if(nodes[i].type == 1){
ssiue[nodes[i].pos] = 1;
sum+=co[nodes[i].pos];
se.insert(nodes[i].pos);
now_num++;
//事件2 预约结尾时间
}else if(ssiue[nodes[i].pos]){
ssiue[nodes[i].pos] = 0;
sum-=co[nodes[i].pos];
se.erase(nodes[i].pos);
now_num--;
}
}
printf("%lld\n",ans);
return 0;
}