zoukankan      html  css  js  c++  java
  • 【分块】【P2801】教主的魔法

    Description

    给你一个长度为 (n) 的序列,要求资瓷区间加,查询区间大于等于 (k) 的数的个数

    Input

    第一行是 (n~,~Q) 代表序列长度和操作个数

    下面一行代表序列

    下面 (Q) 行,每行四个参数,分别为 (opt~,~l,~r~,w)

    如果 (opt~=~M) 则区间加

    如果 (opt~=~A) 则查询

    Output

    对每次查询输出结果

    Hint

    (1~leq~n~leq~1000000~,~1~leq~q~leq~1000)

    Solution

    看到序列这么长,操作数这么少,常见的复杂度平衡的数据结构大概不起作用,于是考虑分块。

    分块后考虑块内如何查询答案:可以对块内整个进行排序,然后lowerbound一下即可。

    考虑修改时,如果修改整个块则不会对块内大小顺序造成影响,可以直接处理。

    边界上直接暴力修改,修改完暴力排序,因为只会暴力两个块,所以复杂度还是 (O(sqrt{n}~(log {sqrt{n}})) 的,总复杂度 (O(q~sqrt{n}~log sqrt{n})),可以通过本题。

    Code

    #include <cmath>
    #include <cstdio>
    #include <algorithm>
    #ifdef ONLINE_JUDGE
    #define freopen(a, b, c)
    #endif
    #define rg register
    #define ci const int
    #define cl const long long
    
    typedef long long int ll;
    
    namespace IPT {
    	const int L = 1000000;
    	char buf[L], *front=buf, *end=buf;
    	char GetChar() {
    		if (front == end) {
    			end = buf + fread(front = buf, 1, L, stdin);
    			if (front == end) return -1;
    		}
    		return *(front++);
    	}
    }
    
    template <typename T>
    inline void qr(T &x) {
    	rg char ch = IPT::GetChar(), lst = ' ';
    	while ((ch > '9') || (ch < '0')) lst = ch, ch=IPT::GetChar();
    	while ((ch >= '0') && (ch <= '9')) x = (x << 1) + (x << 3) + (ch ^ 48), ch = IPT::GetChar();
    	if (lst == '-') x = -x;
    }
    
    template <typename T>
    inline void ReadDb(T &x) {
    	rg char ch = IPT::GetChar(), lst = ' ';
    	while ((ch > '9') || (ch < '0')) lst = ch, ch = IPT::GetChar();
    	while ((ch >= '0') && (ch <= '9')) x = x * 10 + (ch ^ 48), ch = IPT::GetChar();
    	if (ch == '.') {
    		ch = IPT::GetChar();
    		double base = 1;
    		while ((ch >= '0') && (ch <= '9')) x += (ch ^ 48) * ((base *= 0.1)), ch = IPT::GetChar();
    	}
    	if (lst == '-') x = -x;
    }
    
    namespace OPT {
    	char buf[120];
    }
    
    template <typename T>
    inline void qw(T x, const char aft, const bool pt) {
    	if (x < 0) {x = -x, putchar('-');}
    	rg int top=0;
    	do {OPT::buf[++top] = x % 10 + '0';} while (x /= 10);
    	while (top) putchar(OPT::buf[top--]);
    	if (pt) putchar(aft);
    }
    
    const int maxn = 1000010;
    
    int n, q;
    ll MU[maxn], belong[maxn], temp[maxn], tag[maxn], lc[maxn], rc[maxn];
    
    void rebuild(ci);
    
    int main() {
    	freopen("1.in", "r", stdin);
    	qr(n); qr(q);
    	for (rg int i = 1; i <= n; ++i) qr(MU[i]);
    	for (rg int i = 1; i <= n; ++i) temp[i] = MU[i];
    	for (rg int i = 1, sn = sqrt(n); i <= n; ++i) belong[i] = i / sn;
    	for (rg int i = 1, j = 1; i <= n; i = j) {
    		while(belong[j] == belong[i]) ++j;
    		std::sort(temp + i, temp + j);
    		lc[belong[i]] = i; rc[belong[i]] = j;
    	}
    	int a, b, c; rg char ch;
    	while (q--) {
    		do {ch = IPT::GetChar();} while((ch != 'M') && (ch != 'A'));
    		if (ch == 'M') {
    			a = b = c = 0;
    			qr(a); qr(b); qr(c);
    			if (belong[a] == belong[b]) {
    				for (rg int i = a; i <= b; ++i) {
    					MU[i] += c;
    				}
    				rebuild(a);
    			} else {
    				for (rg int i = belong[a] + 1; i < belong[b]; ++i) tag[i] += c;
    				for (rg int i = a; belong[i] == belong[a]; ++i) MU[i] += c;
    				for (rg int i = b; belong[i] == belong[b]; --i) MU[i] += c;
    				rebuild(a); rebuild(b);
    			}
    		} else {
    			a = b = c = 0;
    			qr(a); qr(b); qr(c);
    			int _ret = 0;
    			if (belong[a] == belong[b]) {
    				c -= tag[belong[a]];
    				for (rg int i = a; i <= b; ++i) if (MU[i] >= c) ++_ret;
    			} else {
    				for (rg int i = belong[a] + 1; i < belong[b]; ++i) _ret += temp + rc[i] - std::lower_bound(temp + lc[i], temp + rc[i], c - tag[i]);
    				c -= tag[belong[a]];
    				for (rg int i = a; belong[i] == belong[a]; ++i) _ret += MU[i] >= c;
    				c += tag[belong[a]]; c -= tag[belong[b]];
    				for (rg int i = b; belong[i] == belong[b]; --i)	_ret += MU[i] >= c;
    			}
    			qw(_ret, '
    ', true);
    		}
    	}
    	return 0;
    }
    
    void rebuild(ci a) {
    	for (rg int i = lc[belong[a]]; belong[i] == belong[a]; ++i) temp[i] = MU[i];
    	std::sort(temp + lc[belong[a]], temp + rc[belong[a]]);
    }
    

    Summary

    当查询较少但是序列较长时,考虑分块来降低维护代价。

  • 相关阅读:
    递增三元子序列
    Linux sed 命令
    linux shell中$0,$?,$!等的特殊用法
    ansible-playbook使用
    Linux下通过crontab命令来实现定时任务
    iperf网络性能测试
    OpenStack接口测试工具rally/tempest环境搭建及使用
    Jenkins配置slaver节点
    微信小程序跳转外部链接(h5页面)以及数据交互
    Echarts 系列之折线图、柱状图相关配置
  • 原文地址:https://www.cnblogs.com/yifusuyi/p/10098422.html
Copyright © 2011-2022 走看看