zoukankan      html  css  js  c++  java
  • 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
    "):printf("NIE
    ");
            }
        }
    }
  • 相关阅读:
    【Linux】Linux多个关机命令详解
    【树莓派】树莓派(Debian)- root用户无法使用SSH登录
    【树莓派】树莓派3B安装宝塔面板并配置安装LNMP
    class4/class10/UHS-1/UHS-3 SD卡速度等级区别
    electron-h5-网络状态检测
    electron-消息对话框
    electron-上传文件、保存文件
    electron-子窗口与父窗口通信
    electron-打包
    BrowserView-嵌入网页、open打开子窗口
  • 原文地址:https://www.cnblogs.com/Khada-Jhin/p/9593643.html
Copyright © 2011-2022 走看看