• 洛谷 P3586 [POI2015]LOG


    题目描述

    维护一个长度为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。

     

    输入输出样例

    输入样例#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

    说明

    维护一个长度为n的序列,一开始都是0,支持以下两种操作:

    1.U k a 将序列中第k个数修改为a。

    2.Z c s 在这个序列上,每次选出c个正数,并将它们都减去1,询问能否进行s次操作。

    每次询问独立,即每次询问不会对序列进行修改。

    这道题就是完全树状数组嘛 

    一开始看到这个玩意儿觉得就是建造一颗值域树状数组  然后再查询值大于等于$s$的个数

    如果个数满足大于等于$c$ 那这个玩意儿就是合法的

    但是这个时候也出现了问题 有可能我大于等于$s$的个数不大于$c$ 但是他仍然合法

    比如$2 2 3 6 9$ 我要取出两个数 进行$9$次操作 按照之前的想法这个是不行的 

    但是在这种情况下它可以用多个不同的小数来补齐 那么什么时候才能算是合法的呢

    考虑如果大于等于$s$的个数小于$c$该怎么办 假设大于等于$s$数的个数有$k$个

    那么这个时候除去那$k$个数 剩余我们还需要减去$(c - k) * s$次 就用小于$s$的数的和与这个做比较

    如果大于等于那这个就是合法的 所以还需要维护一颗求数字之和的树状数组

    仔细想一下 这个为什么不会出现小数不够减的情况呢

    因为有先决条件$sum < (c - k) * s$ 又因为不合法的数均是小于$s$ 所以不合法的数的个数一定大于$(c - k)$

    所以我们一定能够选出$(c - k)$ 个数 然后用后面的小数补齐 使它一定够减 就像这样

    一定能够补齐 然后就各种操作搞一搞 要离散化

    代码

    #include <bits/stdc++.h>
    using namespace std;
    
    typedef long long ll;
    const int N = 2 * 1e6 + 5;
    int n,m,tot,t[N],b[N];
    ll c[N],v[N];
    struct option {
        
        int pd,x,y;
    }q[N >> 1],a[N >> 1];
    
    void Init( ) {
        
        scanf("%d%d",& n,& m);
        for(int i = 1;i <= m;i ++) {
            char opt[5];
            ll a,k;
            scanf("%s",opt);
            if(opt[0] == 'U') {
                scanf("%d%d",& a,& k);
                q[i].x = a; q[i].y = k;
                q[i].pd = 1;
                b[++ tot] = k;
            }
            else {
                scanf("%d%d",& a,& k);
                q[i].x = a,q[i].y = k;
                q[i].pd = 0;
            }
        }
        sort(b + 1,b + tot + 1);
        tot = unique(b + 1,b + tot + 1) - b - 1;
    }
    
    int lowbit(int a) {
        
        return a & (-a);
    }
    
    void modify(ll *c, int pos, ll del) {
        
        while(pos <= tot) {
            c[pos] += del;
            pos += lowbit(pos);
        }
    }
    
    ll query(ll *c,int pos) {
        
        ll ans = 0;
        while(pos >= 1) {
            ans += c[pos];
            pos -= lowbit(pos);
        }
        return ans;
    }
    
    void Solve( ) {
        
        for(int i = 1;i <= m;i ++) {
            if(q[i].pd) {
                int pos1 = lower_bound(b + 1, b + tot + 1, t[q[i].x]) - b;
                int num = query(c, pos1) - query(c, pos1 - 1);
                if(num) modify(c, pos1, -1);
                if(num) modify(v, pos1, -t[q[i].x]);
                int pos2 = lower_bound(b + 1, b + tot + 1, q[i].y) - b;
                modify(c, pos2, 1);
                modify(v, pos2, q[i].y);
                t[q[i].x] = q[i].y;
            }
            else {
                int pos = lower_bound(b + 1, b + tot + 1, q[i].y) - b;
                int p = query(c, tot) - query(c, pos - 1);
                ll asum = query(v, tot),bsum = query(v, pos - 1);
                ll num = asum - bsum;
                if(p >= q[i].x) {
                    printf("TAK
    "); continue;
                }
                else if(bsum >= 1ll * (q[i].x - p) * q[i].y) {
                    printf("TAK
    "); continue;
                }
                else printf("NIE
    "); continue;
            }
        }
    }
    
    int main( ) {
        
        Init( );
        Solve( );
    }
  • 相关阅读:
    MyEclipse安装教程以及配置server和运行起来
    倒计时代码-附效果图
    图片循环滚动代码-附效果图
    一个手机页面的导航代码,附效果图
    html电子书翻页效果代码,附效果演示
    唯美雪景雪花飘落代码,附效果演示
    非常漂亮的纯css3实现多彩侧边导航(非常流畅),附效果演示
    页面加密代码,附效果演示
    前端开发每天必学之HTML入门介绍
    仿网易官网顶部展出的大幅广告代码,附效果演示
  • 原文地址:https://www.cnblogs.com/Rubenisveryhandsome/p/9660534.html
Copyright © 2020-2023  润新知