zoukankan      html  css  js  c++  java
  • Luogu 3822 [NOI2017]整数

    看懂了的大佬的题解。(这个id太巨了,找不到他的blog)

    考虑直接暴力算进位均摊复杂度是对的,证明戳这里

    但是题目要求我们支持一个减操作,这就相当于返回之前操作前的结果,这对于这种均摊的复杂度的东西来说简直是不可能的,分分钟$T$飞。

    解决方法也很简单:对加减分别维护一个绝对值,询问的时候相减就好了,这样复杂度也是对的。

    然后考虑询问:因为询问的时候要比较两个绝对值的大小,考虑一下向前面借位的情况, 然后就相当于找一找第$b$位之后的为$1$的位哪个先,这个过程只要在暴力的时候维护一个$set$就可以解决了。

    然后考虑压一下位,这时候就从dalao那里学到了很神奇的$unsigned int$刚好用这玩意压$32$位。

    这个东西有一个好处,就是自动溢出取模,那么加法的时候只要维护一个$tag$,看一下原来的数加上之后是不是比原来小,就可以判断是否有进位了。

    注意到修改和查询的时候其实可能有不完整的块,所以先分别处理一下。

    时间复杂度$O(nlogn)$。

    Code:

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <set>
    using namespace std;
    typedef unsigned int uint;
    
    const int N = 1e6 + 5;
    
    int qn;
    uint inc[N], dec[N];
    set <int> s;
    
    template <typename T>
    inline void read(T &X) {
        X = 0; char ch = 0; T op = 1;
        for(; ch > '9'|| ch < '0'; ch = getchar())
            if(ch == '-') op = -1;
        for(; ch >= '0' && ch <= '9'; ch = getchar())
            X = (X << 3) + (X << 1) + ch - 48;
        X *= op;
    }
    
    int main() {
        int op;
        read(qn), read(op), read(op), read(op);
        for(int a, b; qn--; ) {
            read(op);
            if(op == 1) {
                read(a), read(b);
                int p = (uint)b / 32, q = (uint)b % 32;
                if(a > 0) {
                    uint add = (uint)a << q, tag = (uint)a >> (31 - q); tag >>= 1;
                    uint old = inc[p]; inc[p] += add, tag += (old > inc[p]);
                    if(inc[p] ^ dec[p]) s.insert(p);
                    else if(s.count(p)) s.erase(p);
                    for(++p; tag != 0; ++p) {
                        old = inc[p], inc[p] += tag, tag = (old > inc[p]);
                        if(inc[p] ^ dec[p]) s.insert(p);
                        else if(s.count(p)) s.erase(p);
                    }
                } else {
                    a = -a;
                    uint add = (uint)a << q, tag = (uint)a >> (31 - q); tag >>= 1;
                    uint old = dec[p]; dec[p] += add, tag += (old > dec[p]);
                    if(inc[p] ^ dec[p]) s.insert(p);
                    else if(s.count(p)) s.erase(p);
                    for(++p; tag != 0; ++p) {
                        old = dec[p], dec[p] += tag, tag = (old > dec[p]);
                        if(inc[p] ^ dec[p]) s.insert(p);
                        else if(s.count(p)) s.erase(p);
                    }
                }
            } else {
                read(b);
                int p = b / 32, q = b % 32, ans = (((inc[p] >> q) ^ (dec[p] >> q)) & 1);
                int v1 = inc[p] % (1 << q), v2 = dec[p] % (1 << q);
                if(v1 < v2) printf("%d
    ", ans ^ 1);
                else if(v1 > v2 || s.empty() || p <= (*s.begin())) printf("%d
    ", ans);
                else {
                    set <int> :: iterator it = s.lower_bound(p); --it;
                    if(inc[*it] > dec[*it]) printf("%d
    ", ans);
                    else printf("%d
    ", ans ^ 1);
                }
            }
        }
        return 0;
    }
    View Code
  • 相关阅读:
    redis介绍;特性介绍
    日常2018/4/9---b/s和c/s架构分别是什么?区别?
    持续集成实践---基于ant+jmeter+jenkins接口CI
    面向过程 和 面向对象个人理解
    记一次vc++6.0中程序正常,转 vs2019 c++后报错的问题
    C# 调用C++ dll EntryPointNotFoundException错误
    uniapp踩坑记录(持续更新)
    uniapp引用组件rate评分无法点击引起对style scoped学习
    sql server之time字段详解
    sql server之timestamp字段详解(转)
  • 原文地址:https://www.cnblogs.com/CzxingcHen/p/9568288.html
Copyright © 2011-2022 走看看