HDU 6180 Schedule

最开始发现和之前听某个大佬讲的贪心很像,后来写了好几发都T了,甚至把原来的数组改成了VECTOR,后来发现似乎需要来一发二叉平衡树。。。

此时,队友波塞冬堆出来了最后一题,成功签到,我把题拿给队友,队友表示。。。这不是线段树吗。。。

于是下面是。。。赛中没整出来,但是赛后用自有“ 玄学树状数组 ”堆出来的题解。

设定1,我们要求的东西是:最小的机器启动数量前提下,最小的机器运行时间。

推论1,因而,在每个区间进行+1操作,之后统计最大的点的值即可

推论2,最短运行时间应当有,最后启动的机器,运行到最后,可以得到的时间。例如样例有:
1
3
1 3
4 6
2 5
编号:1  2  3  4  5  6  7
次数:1  2  2  2  1  0  0

如上,在第第一小时,器一台机器启动,在第二小时,第二台机器启动,在第5小时,其中一台机器结束,在第六小时,两台机器都结束。

于是,认为最后结束的应该是最后启动的机器,于是,将【2,6)之间所有数字减一:

编号:1  2  3  4  5  6  7
次数:1  1  1  1  0  0  0

从而得到第二只机器运行时间为6-2(4小时)

之后,发现,此时只有一台机器在运作,因而,关掉这台机器:

编号:1  2  3  4  5  6  7
次数:0  0  0  0  0  0  0

第一台启动的机器运行时间为:5-1=4小时

于是,总运行时间和为8小时,启动机器数量为2小时。

AC代码如下:

#include<bits/stdc++.h>
using namespace std;
/*
*常量MAXN用于设定树状数组的尺寸大小
*/
const long long MAXN=300233;
const long long INF=1e9+233;


class TreeLikeArray
{
    public:
/*
*数组c1用来储存A[i]-A[i-1];
*/
        long long c1[MAXN];
/*
*数组c2用来储存(A[i]-A[i-1])*(i-1);
*或认为用于储存(i-1)*c1[i];
*两种实现方式完全等价
*/
        long long c2[MAXN];
/*
*树状数组的常规操作,参数要求传入数组并指明更新位置,以及更新参数。
*树状数组基础底层操作
*/
        void init()
        {
            memset(c1,0,sizeof(c1));
            memset(c2,0,sizeof(c2));
        }
        void add(long long array[],long long pos,long long key)
    {
        while(pos<MAXN)
        {
            array[pos]+=key;
            pos+=pos&(-pos);
        }
    }
/*
*特别树状数组单点更新操作,要求传入位置和参数
*/
    void add(long long pos,long long key)
    {
        add(c1,pos,key);
        add(c1,pos+1,-key);
        add(c2,pos,(pos-1)*key);
        add(c2,pos+1,-pos*key);
    }
/*
*特别树状数组多点更新操作,要求传入起始位置、终止位置和参数
*该操作将会使得[pos1,pos2]闭区间内所有元素得到更新
*/
    void add(long long pos1,long long pos2,long long key)
    {
        add(c1,pos1,key);
        add(c1,pos2+1,-key);
        add(c2,pos1,(pos1-1)*key);
        add(c2,pos2+1,-pos2*key);
    }
/*
*树状数组的常规操作,参数要求传入数组并指明求和位置
*树状数组基础底层操作
*/
    long long getSum(long long array[],long long pos)
    {
        long long ret=0;
        while(pos>0)
        {
            ret+=array[pos];
            pos-=pos&(-pos);
        }return ret;
    }
/*
*从起始节点到目标节点闭区间求和[0,i]
*/
    long long getSum(long long pos)
    {
        return pos*getSum(c1,pos)-getSum(c2,pos);
    }
/*
*求[pos1,pos2]闭区间内元素和
*/
    long long getSum(long long pos1,long long pos2)
    {
        return getSum(pos2)-getSum(pos1-1);
    }
/*
*求pos单个元素的值
*/
    long long getSingle(long long pos)
    {
        return getSum(pos,pos);
    }
};TreeLikeArray t1;

long long a[MAXN];
long long b[MAXN];
long long c[MAXN];    int n;
long long mach[    MAXN];

long long mapp(long long key)
{
    return lower_bound(c,c+2*n,key)-c+1;
}

void init()
{


    t1.init();
//    memset(mach,0,sizeof(mach));
    cin>>n;
    for(int i=0;i<n;++i)
    {
        cin>>a[i]>>b[i];
        c[i*2]=a[i];
        c[i*2+1]=b[i];
        mach[i]=0;
    }
    sort(c,c+2*n+1);
    for(int i=0;i<n;++i)
    {
        int aa=mapp(a[i]);
        int bb=mapp(b[i]);
        t1.add(aa,bb-1,1);
    }
    long long maxx=0;
    for(int i=1;i<2*n+23;++i)
    {
        int key=t1.getSingle(i);
        if(key>maxx)mach[key]=i,maxx=key;
//        cout<<key<<ends<<mach[key]<<endl;
    }
//    cout<<maxx<<" ";

        long long mm=maxx;
    long long pos=2*n+233;
    long long ans=0;
    while(maxx)
    {
        while(t1.getSingle(pos)<=0)pos--;
//        cout<<c[mach[maxx]-1]<<"  checkpoint "<<c[pos]<<endl;
        
        t1.add(mach[maxx],pos,-1);
        ans+=c[pos]-c[mach[maxx]-1];
        
        if(!mach[maxx-1])mach[maxx-1]=mach[maxx];
        maxx--;
    }
    cout<<mm<<" "<<ans<<"
";
    
    
}

int main()
{
    cin.sync_with_stdio(false);
    int t;cin>>t;
    for(int it=0;it<t;++it)
    init();
}
原文地址:https://www.cnblogs.com/rikka/p/7424882.html