P3776工资管理

时间限制 : - MS 空间限制 : 165536 KB 该题不设总的时间(空间)限制,每组测试数据具有独立的时空限制
评测说明 : 1000ms
问题描述

何老板的公司有n名员工,编号1到n。一开始所有员工的工资都是0。根据何老板的心情好坏,可能出现下列两种针对员工工资的操作:
1.U x y 改工资操作:何老板将第x号员工的工资改成了y;
2.Z x y 减工资操作:何老板生气了,他想选出x个员工,并将他们的工资全都减去1。何老板想知道,他能否一口气进行y次这样的减工资操作。能输出TAK,否则输出NIE。注意,员工的工资不能为负。

对于每个减工资的操作,何老板只是在心里想想,口头上说说,吓唬吓唬大家,解解闷气,他并不会真正执行。即不会对任何人的工资进行修改。

输入格式

第一行包含两个正整数n,m,分别表示员工的人数和操作次数。
接下来m行,每行一个操作,形式如题面所述。

输出格式

包含若干行,对于每个减工资操作,若可行,输出TAK,否则输出NIE。

样例输入 1

3 8
U 1 5
U 2 7
Z 2 6
U 3 1
Z 2 6
U 2 2
Z 2 6
Z 2 1

样例输出 1

NIE
TAK
NIE
TAK

题解

%%%thh
—》http://blog.csdn.net/rgnoH/article/details/75423112
树状数组+离散化

减工资时若有大于等于y则选择这些一定比不选更优,此后若小于y的总资产比 y应减少的更小则一定不行(必要条件),同时也时(充分条件)!详细证明参见上链接。

所以只需要用树状数组维护两个值:1.资产大于等于n的人的数量。2.资产小于等于n的总和。
考虑到x,y的范围为10^9而m的可能情况仅为 2*10^4,采用离散化。

代码

#include <iostream>
#include <cmath>
#include <algorithm>
#include <cstdio>
using namespace std;
#define maxn 400005
#define ll long long 
long long n,m;
long long w[maxn],d[maxn],ord[maxn];
ll val[maxn];
long long sum,tot;
ll num;
inline long long in()
{
    char a=getchar();
    long long tot=0;
    while(a<'0'||a>'9') a=getchar();
    while(a>='0'&&a<='9') {tot=tot*10+a-'0';a=getchar();}
    return tot; 
}
struct node{
    long long k,x,y;
};
node save[maxn];
void modify(ll x,ll y)
{
    int ja=w[x];
    for(;x<=num;x+=(x&(-x)))
    {
        d[x]+=y;
        if(y>0)val[x]+=ja;
        else val[x]-=ja;
    }
}
void getsum(ll x)
{
     tot=0,sum=0;
    for(;x;x-=(x&(-x)))
    {
        tot+=d[x];
        sum+=val[x];
    }
}
int main()
{
    long long i,j,k;
    char t;
    n=in();m=in();
    for(i=1;i<=m;i++)
    {
        long long x,y,z;
        scanf("%c",&t);
        x=in();y=in();
        if(t=='U'){
            save[i].k=0;
            w[i+1]=x;w[i+1+m]=y;
        }
        else save[i].k=1;
       save[i].x=x;save[i].y=y;
    }
    sort(w+1,w+m*2+2);
    num=unique(w+1,w+m*2+2)-w;//unique
    modify(1,n);
    for(i=1;i<=m;i++)
    {
        if(save[i].k==0)
        {
            ll x=save[i].x,y=save[i].y;
            ll wz=lower_bound(w+1,w+1+num,ord[x])-w;
            modify(wz,-1);
            ord[x]=y;
            wz=lower_bound(w+1,w+1+num,y)-w;
            modify(wz,1);
        }
        else{
            ll x=save[i].x,y=save[i].y;
            ll wz2=lower_bound(w+1,w+1+num,y)-w;
            getsum(wz2-1); ll t1=n-tot;
            if((x-t1)*y<=sum) cout<<"TAK"<<endl;
            else cout<<"NIE"<<endl;
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值