JZOJ3639 COCI2013 odasiljaci

来源:互联网 发布:电子签名软件rv2 编辑:程序博客网 时间:2024/05/16 05:06

题目就不贴了。。。
这题。想了一个小时,看题解看了一个小时,打了一个小时,一下午才搞完。。。。。。。

一开始为到底是覆盖还是不覆盖纠结了半天。。好不容易搞明白了题解又把我的定义刚好搞反。。真的烦。

题解(强势翻译一波英文):对于一个区间x,y,我们对于除了x,y以外的发射器忽略,考虑x-y之间的。
假设有若干个发射器,每个能覆盖区间z-y,那么我们可以找到一个最小的z,记为z1。
同理,假设这若干个发射器能覆盖区间x-z,同样可以找到一个最大的z,记为z2.
那么x,y这个区间对于答案的贡献就是y-x-max(0,z1-z2).
现在问题就是如何求z1,z2。很明显我们可以发现,其实z2就是z1倒过来求一波就可以了,所以我们只讨论如何求解z1.
我们首先从左到右扫一遍,用个数据结构(stl速度起飞)维护一下出现过的发射器,接下来我们具体讨论怎么维护。
首先定义一种东西叫做配对点,意思就是,对于每个发射器,他不能覆盖范围的最左(比如样例中第一个发射器的配对点就是2.5)
注意在扫之前先按照x升序排序。
在扫的时候维护一个三元组:x,h,t分别表示发射器的横坐标,高度和配对点。
接下来我们只讨论两个发射器A,B之间的情况(保证A的横坐标小于B的)
1.假如H(A)<=H(B),弹出B,因为A比B优。
2.否则,如果T(A)

#include<cstdio>#include<vector>#include<algorithm>#include<iostream>#define fo(i,x,y) for(int i=x;i<=y;i++)using namespace std;const int N=5e5+5;struct node{    node(int a1):x(a1),y(0){}    node(int a1,int b1):x(a1),y(b1){}    int x,y;};int n,l,t[N],x[N],h[N];double ans[2][N];vector<node> v;double change(const node &ans){    int &x1=x[ans.x],&y1=h[ans.x],    &x2=x[ans.y],&y2=h[ans.y];    return ((double)x1*(y1-y2)-(double)y1*(x1-x2))/(y1-y2);}inline void add(node &ans,int c){    if (change(ans)<change(node(ans.x,c)))    ans.y=c;}int main(){    freopen("odasiljaci.in" , "r" , stdin);    freopen("odasiljaci.out" , "w" , stdout);    scanf("%d%d",&n,&l);    ++n;    fo(i,1,n-1)    scanf("%d%d%d",&t[i],&x[i],&h[i]);    x[n]=l;    ++n;    fo(k,0,1)    {        fo(i,0,n-1)        {            for(;v.size()&&h[v.back().x]<=h[i];v.pop_back());            if (v.size())            {                for(add(v.back(),i);v.size()>1;v.pop_back())                {                    add(v[v.size()-2],i);                    if (change(v.back())<change(v[v.size()-2]))                    break;                }            }            if (t[i])            {                v.push_back(i);                ans[k][i]=x[i];            }            else if (v.size())            ans[k][i]=min(change(v.back()),(double)x[i+1]);            else ans[k][i]=x[i+1];        }        if (!k)        {            reverse(t,t+n);            reverse(x,x+n);            reverse(h,h+n);            fo(i,0,n-1)x[i]=l-x[i];            v.clear();        }    }    reverse(ans[1],ans[1]+n);    fo(i,0,n-1)    ans[1][i]=l-ans[1][i];    double ans1=0;    fo(i,0,n-2)    if (ans[0][i]>ans[1][i+1])    ans1+=ans[0][i]-ans[1][i+1];    printf("%.6lf\n",l-ans1);    return 0;}
0 0
原创粉丝点击