• [SNOI2017]一个简单的询问(莫队+容斥)


    题目描述

    给你一个长度为 (N) 的序列 (a_i)a,(1leq ileq N),和 (q) 组询问,每组询问读入 (l_1,r_1,l_2,r_2),需输出(sumlimits_{x=0}^infty ext{get}(l_1,r_1,x) imes ext{get}(l_2,r_2,x)) 表示计算区间 ([l,r]) 中,数字 (x) 出现了多少次。

    Analysis

    可以离线每次都给你询问一个区间我们很容易想到这是一道莫队题。但这题的询问是两个区间,我们想办法把其拆成一个区间。

    通过容斥,可以得到答案即为 ((get(1,r_1,x)-get(1,l_1)) imes (get(1,r_2,x)-get(1,l_2,x))),拆开后我们发现我们只要解决 (get(1,l,x) imes get(1,r,x)) 的问题。而我们发现这里其实只有两个变量 (l,r)。可是这跟普通的莫队又不太一样,其实只需改一下扩展即可,也就是l减小即删除,增大即增加,r也一样,然后就做完了。

    所以如果这种多个区间的问题以后我们不妨考虑一下化成一个区间。

    记住莫队其实只是排序的过程,而扩展不是不变的,根据不同的问题会有不同的扩展形式,也可能有不同的扩展方法。

    代码的话也非常简短:

    #include <bits/stdc++.h>
    using namespace std;
    const int N = 50010;
    template <typename T> void read(T &x) {
    	T f = 1;
    	char ch = getchar();
    	for (; '0' > ch || ch > '9'; ch = getchar()) if (ch == '-') f = -1;
    	for (x = 0; '0' <= ch && ch <= '9'; ch = getchar()) x = x * 10 + ch - '0';
    	x *= f;
    }
    int n, m;
    int a[N];
    int cnt[2][N];
    int len, bl[N];
    struct node{
    	int l, r, f, id;
    	friend bool operator < (node x, node y) {
    		if (bl[x.l] != bl[y.l]) return x.l < y.l;
    		if (bl[x.l] % 2) return x.r < y.r;
    		return x.r > y.r; 
    	}
    }q[N << 2];
    int ans[N];
    int top;
    int nowl = 0, nowr = 0, nowans = 0;
    void add(int id, int c) {
    	nowans -= cnt[0][c] * cnt[1][c];
    	cnt[id][c]++;
    	nowans += cnt[0][c] * cnt[1][c];
    }
    void del(int id, int c) {
    	nowans -= cnt[0][c] * cnt[1][c];
    	cnt[id][c]--;
    	nowans += cnt[0][c] * cnt[1][c];
    }
    void Push(int l, int r, int f, int id) {
    	if (l > r) swap(l, r);
    	q[++top] = node{l, r, f, id};
    }
    int main() {
    	read(n);
    	for (int i = 1; i <= n; i++) read(a[i]);
    	len = sqrt(n);
    	for (int i = 1; i <= n; i++) bl[i] = (i - 1) / len + 1;
    	read(m);
    	for (int i = 1, l1, r1, l2, r2; i <= m; i++) {
    		read(l1); read(r1); read(l2); read(r2);
    		l1--, l2--;
    		if (l1 == 0 && l2 == 0) {
    			Push(r1, r2, 1, i);
    		} else if (l1 == 0) {
    			Push(r1, r2, 1, i);
    			Push(r1, l2, -1, i);
    		} else if (l2 == 0) {
    			Push(r1, r2, 1, i);
    			Push(l1, r2, -1, i);
    		} else {
    			Push(r1, r2, 1, i);
    			Push(r1, l2, -1, i);
    			Push(l1, r2, -1, i);
    			Push(l1, l2, 1, i);
    		}
    	}
    	sort(q + 1, q + 1 + top);
    	for (int i = 1; i <= top; i++) {
    		while (nowl < q[i].l) add(0, a[++nowl]);
    		while (nowr < q[i].r) add(1, a[++nowr]);
    		while (nowl > q[i].l) del(0, a[nowl--]);
    		while (nowr > q[i].r) del(1, a[nowr--]);
    		ans[q[i].id] += nowans * q[i].f;
    	}
    	for (int i = 1; i <= m; i++) {
    		printf("%d
    ", ans[i]);
    	}
    	return 0;
    }
    
  • 相关阅读:
    many2many
    oneselfone
    one2one
    10-many2one
    08-one2many
    05-curd
    动态SQl
    文件系统缓存dirty_ratio与dirty_background_ratio两个参数区别
    expect用法举例
    通过命令修改mysql的提示符
  • 原文地址:https://www.cnblogs.com/zcr-blog/p/13394550.html
Copyright © 2020-2023  润新知