补题日记[2022牛客暑期多校1]C-Grab the Seat

Posted cls1277

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了补题日记[2022牛客暑期多校1]C-Grab the Seat相关的知识,希望对你有一定的参考价值。

Pro

https://ac.nowcoder.com/acm/contest/33186/C

Sol

通过样例的解释图可以发现,题目其实就是要求一条折线左边的点的个数。而根据一个点可以看到的范围由屏幕的边界确定可以知道,这条折线右侧的图形为图中每一个点与屏幕上下两个点连线包围的面积的并集

考虑如何维护这条折线,对于每个点可以维护两条线的斜率:点与屏幕上方边界的连线;点与屏幕下方边界的连线。接下来考虑为何这样维护可以求面积。

以点与屏幕下方边界的连线为例,我们从小到大枚举纵坐标,对于每个纵坐标如果可以求出折线最右侧的点的横坐标,就可以相减得到未被挡住的点的个数,求和即为答案。

我们知道,当纵坐标从小往大的时候,斜率小的线可能被斜率大的线覆盖,因此我们在枚举的时候保存斜率的最大值,作为最可能挡到该点的线的斜率。

因为我们维护的是斜率,又因为枚举的是纵坐标,所以可以直接求出交点坐标,因为交点坐标可能为整数,所以此处不得不考虑是否可以取到交点的问题。很容易想到,如果该点在视线的连线上,则不可以取到,因此交点的横坐标要减去 e p s eps eps!!!

这样对于枚举的每一个纵坐标可以维护出交点的横坐标的值,对于维护的另一种斜率同理,因为取并集,所以两种情况取最小值。最终交点横坐标的和即为答案。

Code

//By cls1277
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
#define Fo(i,a,b) for(LL i=(a); i<=(b); i++)
#define Ro(i,b,a) for(LL i=(b); i>=(a); i--)
#define Eo(i,x,_) for(LL i=head[x]; i; i=_[i].next)
#define Ms(a,b) memset((a),(b),sizeof(a))
#define endl '\\n'

//const LL maxn = ;

int main() 
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    #ifdef DEBUG
    freopen("data.txt","r",stdin);
    #endif
    LL n, m, k, q; cin>>n>>m>>k>>q;
    vector<set<LL>> a(m+1);
    vector<pair<LL, LL>> b(k+1);
    Fo(i,1,k) 
        LL x, y; cin>>x>>y;
        b[i] = x, y;
        a[y].insert(x);
    
    while(q--) 
        vector<LL> ans(m+1, 0);
        LL id, x, y; cin>>id>>x>>y;
        a[b[id].second].erase(b[id].first);
        b[id] = x, y;
        a[y].insert(x);
        Fo(i,1,m) 
            if(!a[i].size()) ans[i] = n;
            else ans[i] = (*a[i].begin())-1;
        
        double mx = 0;
        Fo(i,2,m) 
            if(mx) ans[i] = (int)min((double)ans[i], (i-1)*1.0/mx-(1e-6));
            if(!a[i].size()) continue;
            double k = (i-1)*1.0/(*a[i].begin());
            mx = max(mx, k);
        
        mx = 0;
        Ro(i,m-1,1) 
            if(mx) ans[i] = (int)min((double)ans[i], (i-m)*1.0/mx-(1e-6));
            if(!a[i].size()) continue;
            double k = (i-m)*1.0/(*a[i].begin());
            mx = min(mx, k);
        
        LL res = 0;
        Fo(i,1,m) res+=ans[i];
        cout<<res<<endl;
    
    return 0;


以上是关于补题日记[2022牛客暑期多校1]C-Grab the Seat的主要内容,如果未能解决你的问题,请参考以下文章

补题日记[2022牛客暑期多校4]A-Task Computing

补题日记[2022牛客暑期多校4]A-Task Computing

补题日记[2022牛客暑期多校1]J-Serval and Essay

补题日记[2022牛客暑期多校1]D-Mocha and Railgun

补题日记[2022牛客暑期多校2]H-Take the Elevator

补题日记[2022牛客暑期多校2]H-Take the Elevator