【NKOJ3776】工资管理

问题描述

何老板的公司有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

样例输入 2

13 17
U 1 12
Z 1 9
Z 1 5
Z 4 7
U 7 18
Z 1 1
Z 1 8
U 6 4
U 1 9
U 3 13
Z 5 2
U 7 8
U 4 20
U 7 14
Z 6 1
Z 3 2
Z 8 7

样例输出 2

TAK
TAK
NIE
TAK
TAK
NIE
NIE
TAK
NIE

数据范围

对于30%的数据:1<=n,m<=1000
对于100%的数据:1<=n,m<=200000 1<=x<=n,0<=y<=10^9,1<=y<=10^9


题解

这道题看着很迷。。。
显然,对于某一组询问(x,y),如果一个人的工资大于y,无论有多高,这个人对扣除总工资的贡献都只能为y(毕竟一个人只能减y次)。而对于工资小于或等于y 的人来说,只要分配合理,他们的工资是可以完全利用的。
因此,设工资超过y 的人有k个,不超过y 的人的工资总和为sum,老板能完成操作当且仅当sum+y*k>=x*y。
然后考虑如何实现。
可以用俩树状数组。点修改和区间查询都能实现。具体见代码。
但是,考试时zz了一下,把方法看成了求第k小,就打了棵splay。发现错误后,改十几行就能通过。However,它的代码量是树状数组的3倍,时间是树状数组的2倍多,NKOJ甚至不加头文件优化过不了。。应该没人用这种方法。。。


代码

1:树状数组

#include <cstdio>
#include <iostream>
#include <algorithm>
#define int long long
using namespace std;

int maxn,u[2][1000000]={0};
int lb(int x)
{return x&(-x);}
void MDF(int x,int v,int q)
{while(x<=maxn)u[q][x]+=v,x+=lb(x);}
int SUM(int x,int q)
{int t=0;while(x)t+=u[q][x],x-=lb(x);return t;}

int uni[1000000],a[200005];

struct dt{
    bool g;
    int x,y;
}que[200005];
main()
{
    int i,n,m;
    scanf("%lld%lld",&n,&m);
    for(i=1;i<=m;i++){
        char o=getchar();
        while(o!='U'&&o!='Z')o=getchar();
        scanf("%lld%lld",&que[i].x,&que[i].y);
        que[i].g=(o=='U');
        uni[i]=que[i].y;
    }
    uni[m+1]=0;
    sort(uni+1,uni+m+2);
    maxn=unique(uni+1,uni+m+2)-uni-1;
    for(i=1;i<=n;i++)a[i]=1;
    MDF(1,n,0);
    for(i=1;i<=m;i++)
        if(que[i].g){
            int x=que[i].x,y=lower_bound(uni+1,uni+maxn+1,que[i].y)-uni;
            MDF(a[x],-1,0);
            MDF(a[x],-uni[a[x]],1);
            a[x]=y;
            MDF(a[x],1,0);
            MDF(a[x],uni[a[x]],1);
        }
        else{
            int x=que[i].x,y=lower_bound(uni+1,uni+maxn+1,que[i].y)-uni;
            int k=SUM(maxn,0)-SUM(y-1,0),yox=SUM(y-1,1);
            yox>=(x-k)*que[i].y?puts("TAK"):puts("NIE");
        }
    return 0;
}

2:平衡树

#include <cstdio>
#include <cstdlib>
#include <iostream>
#define ll long long
using namespace std;
const int Q=2000000;
int ls[Q],rs[Q],f[Q],si[Q],cnt[Q],root=0,tot;
ll v[Q],sum[Q];
void upd(int y)
{sum[y]=sum[ls[y]]+sum[rs[y]]+v[y]*cnt[y];}
void lx(int x)
{
    int y=f[x],z=f[y];
    if(z)if(ls[z]==y)ls[z]=x;
    else rs[z]=x;
    f[x]=z;
    rs[y]=ls[x];
    f[rs[y]]=y;
    ls[x]=y;
    f[y]=x;
    si[x]=si[y];
    si[y]=si[ls[y]]+si[rs[y]]+cnt[y];
    upd(y);upd(x);
}
void rx(int x)
{
    int y=f[x],z=f[y];
    if(z)if(ls[z]==y)ls[z]=x;
    else rs[z]=x;
    f[x]=z;
    ls[y]=rs[x];
    f[ls[y]]=y;
    rs[x]=y;
    f[y]=x;
    si[x]=si[y];
    si[y]=si[ls[y]]+si[rs[y]]+cnt[y];
    upd(y);upd(x);
}
void splay(int x)
{
    while(f[x]){
        int y=f[x],z=f[y];
        if(z)
            if(ls[z]==y)
                if(ls[y]==x)rx(y),rx(x);
                else lx(x),rx(x);
            else if(rs[y]==x)lx(y),lx(x);
                else rx(x),lx(x);
        else if(ls[y]==x)rx(x);
            else lx(x);
    }
    root=x;
}
int ins(ll y)
{
    if(!root){
        root=++tot;
        si[tot]=cnt[tot]=1;
        v[tot]=sum[tot]=y;
        return tot;
    }
    int t=root;
    while(t)
    {
        ++si[t];
        sum[t]+=y;
        if(v[t]==y)
        {cnt[t]++;return t;}
        if(y<v[t])
            if(ls[t])t=ls[t];
            else {ls[t]=++tot;break;}
        else if(rs[t])t=rs[t];
            else {rs[t]=++tot;break;}
    }
    f[tot]=t;
    v[tot]=sum[tot]=y;
    si[tot]=cnt[tot]=1;
    splay(tot);
    return tot;
}
int fin(ll y)
{
    int t=root;
    while(t)
    {
        if(v[t]==y&&cnt[t])return t;
        if(y<v[t])t=ls[t];
        else t=rs[t];
    }
    return -1;
}
void del(int x)
{
    splay(x);
    if((--cnt[x])>0){--si[x];return;}
    int lls=ls[x],rrs=rs[x];
    f[lls]=f[rrs]=ls[x]=rs[x]=si[x]=0;
    if(!lls){root=rrs;return;}
    root=lls;
    while(rs[lls])lls=rs[lls];
    splay(lls);
    rs[lls]=rrs;
    f[rrs]=lls;
    si[lls]+=si[rrs];
}
ll a[200005];
int main()
{
    int i,n,m,x;
    ll y;
    scanf("%d%d",&n,&m);
    srand(n+m);
    for(i=1;i<=n;i++)
        ins(0);
    while(m--){
        char o=getchar();
        while(o!='U'&&o!='Z')o=getchar();
        scanf("%d%lld",&x,&y);
        if(o=='U'){
            del(fin(a[x]));
            int p=fin(a[x]);
            a[x]=y;
            ins(a[x]);
        }
        else{
            int p=root;
            int gee=ins(y);
            splay(gee);
            ll temp=(ll)sum[ls[gee]]+(si[rs[gee]]+cnt[gee]-1)*y;
            if(temp>=(ll)x*(ll)y)puts("TAK");
            else puts("NIE");
            del(gee);
        }
        splay(fin(a[rand()%n+1]));
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/includelhc/article/details/80795169