JZOJ3639 COCI2013 odasiljaci

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

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

题解(强势翻译一波英文):对于一个区间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
#include
#include
#include
#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 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)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())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;
}

你可能感兴趣的:(jzoj,神奇脑洞题)