BZOJ4378[POI2015]Logistyka——树状数组

题目描述

维护一个长度为n的序列,一开始都是0,支持以下两种操作:
1.U k a 将序列中第k个数修改为a。
2.Z c s 在这个序列上,每次选出c个正数,并将它们都减去1,询问能否进行s次操作。
每次询问独立,即每次询问不会对序列进行修改。

输入

第一行包含两个正整数n,m(1<=n,m<=1000000),分别表示序列长度和操作次数。
接下来m行为m个操作,其中1<=k,c<=n,0<=a<=10^9,1<=s<=10^9。

输出

包含若干行,对于每个Z询问,若可行,输出TAK,否则输出NIE。

样例输入

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

样例输出

NIE
TAK
NIE
TAK
  对于每次询问,设大于等于s的数有k个,那么如果剩下数的和sum>=(c-k)*s,剩下数中每次取最大的(c-k)个就一定能进行s次(证明在最后)。只要离散化一下之后用树状数组维护一下区间个数及区间和就好了。
证明:
首先大于等于s的k个数一定能取s次,设p=c-k,如果取了z次后取不了了,也就是剩下的数不足p个,因为剩下的数之和一定>=p*(s-z),那么剩下的数之中一定有大于s-z的,在取z次之前这个数就大于s了,与上面矛盾,因此只要sum>=p*s就一定能进行s次,反之因为和都小于s,就一定取不了s次。
#include<set>
#include<map>
#include<queue>
#include<cmath>
#include<stack>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int n,m;
int cnt;
char s[20];
int a[1000010];
int b[1000010];
int c[1000010];
int d[1000010];
int e[1000010];
int h[1000010];
struct node
{
    long long v[1000010];
    void add(int x,int t)
    {
        for(;x<=cnt;x+=x&-x)
        {
            v[x]+=t;
        }
    }
    long long query(int x)
    {
        long long res=0;
        for(;x;x-=x&-x)
        {
            res+=v[x];
        }
        return res;
    }
}b1,b2;
int find(int x)
{
    int l=1,r=cnt,mid;
    while(l<r)
    {
        mid=(l+r)>>1;
        if(h[mid]<x) 
        {
            l=mid+1;    
        }
        else
        {
            r=mid;
        }
    }
    return l;
}
int main()
{
    int num;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        scanf("%s",s);
        scanf("%d%d",&b[i],&c[i]);
        e[i]=c[i];
        if(s[0]=='U')
        {
            d[i]=1;
        }
    }
    sort(e+1,e+m+1);
    h[++cnt]=e[1];
    for(int i=2;i<=m;i++)
    {
        if(e[i]!=e[i-1])
        {
            h[++cnt]=e[i];
        }
    }
    for(int i=1;i<=m;i++)
    {
        c[i]=find(c[i]);
    }
    for(int i=1;i<=m;i++)
    {
        if(d[i])
        {
            if(num=a[b[i]])
            {
                b1.add(num,-1);
                b2.add(num,-h[num]);
            }
            a[b[i]]=c[i];
            b1.add(c[i],1);
            b2.add(c[i],h[c[i]]);
        }
        else
        {
            b2.query(c[i]-1)>=(b[i]-b1.query(cnt)+b1.query(c[i]-1))*h[c[i]]?printf("TAK\n"):printf("NIE\n");
        }
    }
}
posted @ 2018-09-05 18:01  The_Virtuoso  阅读(210)  评论(0编辑  收藏  举报