SGU 311 Ice-cream Tycoon(线段树)

题目链接:http://acm.sgu.ru/problem.php?contest=0&problem=311

题意:一个商店,有两种操作:(1)ARRIVE n c表示进货n个,每个c元。(2)BUY n t表示一个买货的人要买n个,一共拿了t元钱。如果现在店里的货的数量大于等于n且最便宜的n个的价格小于等于t则将最便宜的卖给他。否则不卖。

思路:线段树的节点保存该段货物的数量和总价格,另外增加一个标志标记该段内是否被卖完。标记每次向下传递。注意在计算最便宜的n个的价格时向下传递标志时要向上更新sum和value值。因为若这次不向上更新,若本次的价格和大于t则不会再进行删掉前n个的操作,就会出错。





const int N=100005;

const int M=300005;



struct query

{

    char cmd[10];

    i64 n,c;

};



struct node

{

    i64 sum,value;

    int L,R,mid,flag;

};



query q[N];

vector<i64> V;

map<i64,int> Map;

int n,m;

node a[M];



void build(int t,int L,int R)

{

    a[t].L=L;

    a[t].R=R;

    a[t].mid=(L+R)>>1;

    a[t].flag=0;

    a[t].sum=a[t].value=0;

    if(L==R) return;

    build(t*2,L,a[t].mid);

    build(t*2+1,a[t].mid+1,R);

}



void mark(int u)

{

    if(u>M) return;

    a[u].flag=1;

    a[u].sum=a[u].value=0;

}



void down(int t)

{

    if(t>M||!a[t].flag) return;

    a[t].flag=0;

    mark(t*2);mark(t*2+1);

}



void up(int t)

{

    a[t].sum=a[t*2].sum+a[t*2+1].sum;

    a[t].value=a[t*2].value+a[t*2+1].value;

}



void insert(int t,int pos,i64 n)

{

    down(t);

    if(a[t].L==a[t].R)

    {

        a[t].sum+=n;

        a[t].value+=V[pos-1]*n;

        return;

    }

    if(pos<=a[t].mid) insert(t*2,pos,n);

    else insert(t*2+1,pos,n);

    up(t);

}





i64 get(int t,i64 n)

{

    down(t);

    if(n==a[t].sum) return a[t].value;

    if(a[t].L==a[t].R) return a[t].value/a[t].sum*n;

    up(t);

    if(n<=a[t*2].sum) return get(t*2,n);

    return a[t*2].value+get(t*2+1,n-a[t*2].sum);

}



void del(int t,i64 n)

{

    down(t);

    if(n==a[t].sum)

    {

        mark(t);

        return;

    }

    if(a[t].L==a[t].R)

    {

        a[t].value-=a[t].value/a[t].sum*n;

        a[t].sum-=n;

        return;

    }

    if(n<=a[t*2].sum) del(t*2,n);

    else

    {

        del(t*2+1,n-a[t*2].sum);

        mark(t*2);

    }

    up(t);

}



void deal(i64 n,i64 t)

{

    if(a[1].sum<n||get(1,n)>t) puts("UNHAPPY");

    else puts("HAPPY"),del(1,n);

}





int main()

{

    while(scanf("%s%lld%lld",q[n+1].cmd,&q[n+1].n,&q[n+1].c)!=-1)

    {

        n++;

        if(q[n].cmd[0]=='A') V.pb(q[n].c);

    }

    sort(V.begin(),V.end());

    m=unique(V.begin(),V.end())-V.begin();

    int i,k;

    FOR0(i,m) Map[V[i]]=i+1;

    build(1,1,m);

    FOR1(i,n)

    {

        if(q[i].cmd[0]=='A')

        {

            k=Map[q[i].c];

            insert(1,k,q[i].n);

        }

        else deal(q[i].n,q[i].c);

    }

	return 0;

}

  

你可能感兴趣的:(线段树)