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\n", ans ^ 1);
            else if(v1 > v2 || s.empty() || p <= (*s.begin())) printf("%d\n", ans);
            else {
                set <int> :: iterator it = s.lower_bound(p); --it;
                if(inc[*it] > dec[*it]) printf("%d\n", ans);
                else printf("%d\n", ans ^ 1);
            }
        }
    }
    return 0;
}
View Code

 

posted @ 2018-08-31 21:11  CzxingcHen  阅读(165)  评论(0编辑  收藏  举报