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

    题目大意:有一个整数 $x$ ,一开始为 $0$ 。有 $n$ 个操作,有两种类型:

    $1 ;a; b$:将 $x$ 加上整数 $acdot 2^b$ ,其中 $a$ 为一个整数, $b$ 为一个非负整数

    $2; k$ :询问 $x$ 在用二进制表示时,第 $2^k$ 位的值($0$或$1$)

    保证在任何时候, $xgeq 0$ 。

    题解:压位线段树,每一个节点压$30$位,考虑到有加减操作,而对于加操作,只是把这一位前的第一个$0$变成$1$,把其间的$1$变成$0$,减相反。所以我们可以在线段树中存一下区间$AND$和区间$OR$,找到某一位前的第一个$1$或第一个$0$,线段树修改一下就行了

    卡点:线段树中的$update$和$pushdown$中把$rc$写成了$rt$($QAQ$)

    C++ Code:

    #include <cstdio>
    #include <cstring>
    #define base 30
    #define maxn 1000010
    using namespace std;
    const int inf = (1 << base) - 1;
    int n, op;
    struct ST {
    	int And[maxn << 2], Or[maxn << 2], V[maxn << 2], tg[maxn << 2];
    	void init() {
    		memset(tg, -1, sizeof tg);
    	}
    	void pushdown(int rt) {
    		int lc = rt << 1, rc = rt << 1 | 1, &tmp = tg[rt];
    		And[lc] = Or[lc] = tg[lc] = tmp;
    		And[rc] = Or[rc] = tg[rc] = tmp;
    		tmp = -1;
    	}
    	void update(int rt) {
    		int lc = rt << 1, rc = rt << 1 | 1;
    		And[rt] = And[lc] & And[rc];
    		Or[rt] = Or[lc] | Or[rc];
    	}
    	void add(int rt, int l, int r, int p, int num) {
    		if (l > r) return ;
    		if (l == r) {
    			Or[rt] = And[rt] = num;
    			return ;
    		}
    		int mid = l + r >> 1;
    		if (~tg[rt]) pushdown(rt);
    		if (p <= mid) add(rt << 1, l, mid, p, num);
    		else add(rt << 1 | 1, mid + 1, r, p, num);
    		update(rt);
    	}
    	void add(int rt, int l, int r, int L, int R, int num) {
    		if (l > r || L > R) return ;
    		if (L <= l && R >= r) {
    			Or[rt] = And[rt] = tg[rt] = num;
    			return ;
    		}
    		int mid = l + r >> 1;
    		if (~tg[rt]) pushdown(rt);
    		if (L <= mid) add(rt << 1, l, mid, L, R, num);
    		if (R > mid) add(rt << 1 | 1, mid + 1, r, L, R, num);
    		update(rt);
    	}
    	int ask(int rt, int l, int r, int p) {
    		if (l > r) return 0;
    		if (l == r) return And[rt];
    		int mid = l + r >> 1, ans;
    		if (~tg[rt]) pushdown(rt);
    		if (p <= mid) ans = ask(rt << 1, l, mid, p);
    		else ans = ask(rt << 1 | 1, mid + 1, r, p);
    		return ans;
    	}
    	int find_1(int rt, int l, int r, int p) {
    		if (Or[rt] == 0) return -1;
    		if (l == r) return l;
    		int mid = l + r >> 1;
    		if (~tg[rt]) pushdown(rt);
    	    if (p <= mid) {
    	        int tmp = find_1(rt << 1, l, mid, p);
    	        return ~tmp ? tmp : find_1(rt << 1 | 1, mid + 1, r, p);
    	    } else return find_1(rt << 1 | 1, mid + 1, r, p);
    	}
    	int find_0(int rt, int l, int r, int p) {
    		if (And[rt] == inf) return -1;
    		if (l == r) return l;
    		int mid = l + r >> 1;
    		if (~tg[rt]) pushdown(rt);
    	    if (p <= mid) {
    	        int tmp = find_0(rt << 1, l, mid, p);
    	        return ~tmp ? tmp : find_0(rt << 1 | 1, mid + 1, r, p);
    	    } else return find_0(rt << 1 | 1, mid + 1, r, p);
    	}
    } T;
    void inc(int p, int num) {
    	if (!num) return ;
    	int tmp = T.ask(1, 0, maxn, p) + num;
    	if (tmp <= inf) T.add(1, 0, maxn, p, tmp);
    	else {
    		T.add(1, 0, maxn, p, tmp & inf);
    		int pos = T.find_0(1, 0, maxn, p + 1);
    		T.add(1, 0, maxn, p + 1, pos - 1, 0);
    		inc(pos, 1);
    	}
    }
    void dec(int p, int num) {
    	if (!num) return ;
    	int tmp = T.ask(1, 0, maxn, p) - num;
    	if (tmp >= 0) T.add(1, 0, maxn, p, tmp);
    	else {
    		T.add(1, 0, maxn, p, tmp + inf + 1);
    		int pos = T.find_1(1, 0, maxn, p + 1);
    		T.add(1, 0, maxn, p + 1, pos - 1, inf);
    		dec(pos, 1);
    	}
    }
    void modify(int a, int b) {
    	int blo = b / base, num = b % base;
    	if (a > 0) {
    		inc(blo, (a << num) & inf);
    		a = a >> base - num;
    		if (a) inc(blo + 1, a);
    	} else {
    		a = -a;
    		dec(blo, (a << num) & inf);
    		a = a >> base - num;
    		if (a) dec(blo + 1, a);
    	}
    }
    int query(int k) {
    	int tmp = T.ask(1, 0, maxn, k / base);
    	return (tmp & (1 << k % base)) && 1;
    }
    int main() {
    //	freopen("integer.in", "r", stdin);
    //	freopen("integer.out" ,"w", stdout);
    	scanf("%d%*d%*d%*d", &n);
    	T.init();
    	while (n--) {
    		scanf("%d", &op);
    		if (op --> 1) {
    			int k;
    			scanf("%d", &k);
    //			printf("%d
    ", k);
    			printf("%d
    ", query(k));
    //			puts("query");
    		} else {
    			int a, b;
    			scanf("%d%d", &a, &b);
    			if (!a) continue;
    			modify(a, b);
    //			puts("modify");
    		}
    	}
    	return 0;
    }
    

      

  • 相关阅读:
    git创建、删除分支
    Git 基础
    python pillow
    phantomjs 下载
    python3安装PIL
    selenium打开chrome时,出现 "您使用的是不受支持的命令行标记:--ignore-certificate-errors""
    chrome driver 下载
    go 单进程并发
    go 内嵌对象类型
    go 多态
  • 原文地址:https://www.cnblogs.com/Memory-of-winter/p/9463961.html
Copyright © 2011-2022 走看看