时间限制 : - 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;
}
}
}