zoukankan      html  css  js  c++  java
  • BZOJ-1568: Blue Mary开公司 (李超线段树)

    Description

    Input

    第一行 :一个整数N ,表示方案和询问的总数。 接下来N行,每行开头一个单词“Query”或“Project”。 若单词为Query,则后接一个整数T,表示Blue Mary询问第T天的最大收益。 若单词为Project,则后接两个实数S,P,表示该种设计方案第一天的收益S,以及以后每天比上一天多出的收益P。

    Output

    对于每一个Query,输出一个整数,表示询问的答案,并精确到整百元(以百元为单位,例如:该天最大收益为210或290时,均应该输出2)。

    Sample Input

    10
    Project 5.10200 0.65000
    Project 2.76200 1.43000
    Query 4
    Query 2
    Project 3.80200 1.17000
    Query 2
    Query 3
    Query 1
    Project 4.58200 0.91000
    Project 5.36200 0.39000

    Sample Output

    0
    0
    0
    0
    0

    约定: 1 <= N <= 100000 1 <= T <=50000 0 < P < 100,| S | <= 10^6

    提示:本题读写数据量可能相当巨大,请选手注意选择高效的文件读写方式。

    题意:给定多个线段,以及多个询问,回答的是在某个位置,线段最高的值。

    思路:当年题解好像是splay。后来可以用超哥线段树来做。

     超哥线段树的节点node保存的是某线段X的id,当且当这个线段X的在这个节点node代表的区间的中点处最高(或者最低),比如下图的1线段在Mid处最高。

    更新的时候(加入新的线段Y),如果它在node的mid位置比原来的线段在mid位置高,那么Y会取代原来的值。但是原来的值或者Y可能在左区间或者右区间可以最高,所以需要下推。 下面给个妮子:

                            

    假设此node原来保存的是线段2,现在加线段1,发现1线段的Mid大于2,所以替换。但是发现2线段在左边部分有一段是最高的,所以需要用2线段去更新左半部分。即更新部分有4种情况:

    void update(int Now,int L,int R,int x)
    {
        int Mid=(L+R)>>1; 
        if(L==R){ if(comp(x,Mx[Now],Mid)) Mx[Now]=x; return ; }
        if(p[x]>p[Mx[Now]]){
            //下传的时候是传的可以更新的区域(左或者右),更新的val是哪个区域可能大的那个(x或者Mx[Now]) 
            if(comp(x,Mx[Now],Mid)) update(Now<<1,L,Mid,Mx[Now]),Mx[Now]=x;
            else update(Now<<1|1,Mid+1,R,x); 
        }
        if(p[x]<p[Mx[Now]]){
            if(comp(x,Mx[Now],Mid)) update(Now<<1|1,Mid+1,R,Mx[Now]),Mx[Now]=x;
            else update(Now<<1,L,Mid,x); 
        }
    }

    或者更直观的版本:

    
    
    void update(int Now,int L,int R,int x)
    {
        int Mid=(L+R)>>1; 
        if(L==R){ if(comp(x,Mx[Now],Mid)) Mx[Now]=x; return ; }
        if(comp(x,Mx[Now],Mid)){  //只针对着两条线段比较 
            if(comp(Mx[Now],x,L)) update(Now<<1,L,Mid,Mx[Now]);  //任然是比较这两条线段
            if(comp(Mx[Now],x,R)) update(Now<<1|1,Mid+1,R,Mx[Now]);
            Mx[Now]=x; 
        }
        else {
            if(comp(x,Mx[Now],L)) update(Now<<1,L,Mid,x);
            if(comp(x,Mx[Now],R)) update(Now<<1|1,Mid+1,R,x);
        }
    }

    而查询位置x的时候,从根到L==R==x这个过程都要去更新最大值。

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=500003,M=50000;
    int n,Mx[maxn*4],cnt;
    double s[maxn*2],p[maxn*2];
    int comp(int x,int y,int pos) { return s[x]+(pos-1)*p[x]>s[y]+(pos-1)*p[y];}
    double getans(int x,int pos){ return s[x]+(pos-1)*p[x]; }
    void update(int Now,int L,int R,int x)
    {
        int Mid=(L+R)>>1; 
        if(L==R){ if(comp(x,Mx[Now],Mid)) Mx[Now]=x; return ; }
        if(p[x]>p[Mx[Now]]){
            if(comp(x,Mx[Now],Mid)) update(Now<<1,L,Mid,Mx[Now]),Mx[Now]=x;
            else update(Now<<1|1,Mid+1,R,x); 
        }
        if(p[x]<p[Mx[Now]]){
            if(comp(x,Mx[Now],Mid)) update(Now<<1|1,Mid+1,R,Mx[Now]),Mx[Now]=x;
            else update(Now<<1,L,Mid,x); 
        }
    }
    double query(int Now,int L,int R,int pos)
    {
        if(L==R) return getans(Mx[Now],pos); 
        int Mid=(L+R)>>1; double ans=getans(Mx[Now],pos);
        if(pos<=Mid) return max(ans,query(Now<<1,L,Mid,pos));
        else return max(ans,query(Now<<1|1,Mid+1,R,pos));
    }
    int main()
    {
        int N; scanf("%d",&N);
        while(N--){
            char c[20]; scanf("%s",c);
            if(c[0]=='P'){
                cnt++; scanf("%lf%lf",&s[cnt],&p[cnt]);
                update(1,1,M,cnt);
            }
            else {
                int x; scanf("%d",&x);
                double ans=query(1,1,M,x);
                printf("%d
    ",(int)ans/100);
            }
        }
        return 0;
    }

    更直观的版本2:

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=500003,M=50000;
    int n,Mx[maxn*4],cnt;
    double s[maxn*2],p[maxn*2];
    int comp(int x,int y,int pos) { return s[x]+(pos-1)*p[x]>s[y]+(pos-1)*p[y];}
    double getans(int x,int pos){ return s[x]+(pos-1)*p[x]; }
    void update(int Now,int L,int R,int x)
    {
        int Mid=(L+R)>>1; 
        if(L==R){ if(comp(x,Mx[Now],Mid)) Mx[Now]=x; return ; }
        if(comp(x,Mx[Now],Mid)){  //只针对着两条线段比较 
            if(comp(Mx[Now],x,L)) update(Now<<1,L,Mid,Mx[Now]);  //任然是比较这两条线段?
            if(comp(Mx[Now],x,R)) update(Now<<1|1,Mid+1,R,Mx[Now]);
            Mx[Now]=x; 
        }
        else {
            if(comp(x,Mx[Now],L)) update(Now<<1,L,Mid,x);
            if(comp(x,Mx[Now],R)) update(Now<<1|1,Mid+1,R,x);
        }
    }
    double query(int Now,int L,int R,int pos)
    {
        if(L==R) return getans(Mx[Now],pos); 
        int Mid=(L+R)>>1; double ans=getans(Mx[Now],pos);
        if(pos<=Mid) return max(ans,query(Now<<1,L,Mid,pos));
        else return max(ans,query(Now<<1|1,Mid+1,R,pos));
    }
    int main()
    {
        int N; scanf("%d",&N);
        while(N--){
            char c[20]; scanf("%s",c);
            if(c[0]=='P'){
                cnt++; scanf("%lf%lf",&s[cnt],&p[cnt]);
                update(1,1,M,cnt);
            }
            else {
                int x; scanf("%d",&x);
                double ans=query(1,1,M,x);
                printf("%d
    ",(int)ans/100);
            }
        }
        return 0;
    }
  • 相关阅读:
    hihoCoder#1128 二分·二分查找
    hihoCoder#1127 二分图三·二分图最小点覆盖和最大独立集
    hihoCoder#1122 二分图二•二分图最大匹配之匈牙利算法
    hihoCoder#1105 题外话·堆
    Ajax详细剖析
    web框架之--Tornado
    web框架之--先来个介绍
    前端之--Jquery-玩穿它!
    前端之--DOM详解应用
    前端之--JavaScript作用域--超细讲解
  • 原文地址:https://www.cnblogs.com/hua-dong/p/9269342.html
Copyright © 2011-2022 走看看