zoukankan      html  css  js  c++  java
  • Solution -「洛谷 P4688」「YunoOI 2016」掉进兔子洞

    Description

    (Link)[https://www.luogu.com.cn/problem/P4688].

    每次询问三个区间,把三个区间中同时出现的数一个一个删掉,问最后三个区间剩下的数的个数和,询问独立。

    Solution

    读完题,我们可以发现每轮询问的答案是这个东西:

    [sum_{i=1}^{3}(r_{i}-l_{i}+1)-P imes 3 ]

    其中,(P) 表示三个区间里面的公共颜色数量。

    前面那个 (sum) 里面的东西很好维护,我们主要来讲后面一部分的维护方法。

    首先初始序列的 (a_{i}) 是一定要离散化一遍的。

    那么我们如何表示出出现的最少次数呢?

    如果这是一个二进制串的话,我们可以发现这就是一个 (operatorname{bit\_and}) 的操作。

    对于每个询问,我们可以把三个区间分开处理再合并。直接维护复杂度过高,用 bitset 优化。由于这是个二进制序列,所以离散化的时候不能去重,否则答案就会偏大。

    直接操作容易 MLE,这里介绍一个小trick。我们可以把询问分批处理,这样就行了。

    #include <cstdio>
    #include <iostream>
    #include <algorithm>
    #include <cstring>
    #include <queue>
    #include <bitset>
    #include <cmath>
    
    using namespace std;
    typedef long long LL;
    typedef unsigned long long ULL;
    
    const int N = 1e5 + 5;
    const int F = 23333 + 5;
    int n, m, block, origin[N], appear[N];
    int cnt[N], ans[N], vis[25005];
    int l1[N], l2[N], l3[N];
    int r1[N], r2[N], r3[N];
    bitset < N > S[F];
    vector < int > disc;
    struct AskSet {
    	int l, r;
    	int id, p;
    } Q[N];
    
    int GetID(int x) {
    	return lower_bound(disc.begin(), disc.end(), x) - disc.begin() + 1;
    }
    
    bool SortWith(const AskSet& x, const AskSet& y) {
    	return (x.p < y.p) || (x.p == y.p && x.r < y.r);
    }
    
    void MakeCont(int pos, int flags, bitset < N >& bit) {
    	pos = origin[pos];
    	if (flags > 0) bit[pos + cnt[pos]] = 1;
    	else bit[pos + cnt[pos] - 1] = 0;
    	cnt[pos] += flags;
    }
    
    void Contribute(int fr, int ba) {
    	memset(cnt, 0, sizeof cnt);
    	memset(vis, 0, sizeof vis);
    	bitset < N > bit; bit.reset();
    	int l = 1, r = 0, subs = 0;
    	for (int i = fr; i <= ba; ++i) {
    		Q[++subs] = {l1[i], r1[i], i, appear[l1[i]]};
    		Q[++subs] = {l2[i], r2[i], i, appear[l2[i]]};
    		Q[++subs] = {l3[i], r3[i], i, appear[l3[i]]};
    		ans[i] += (r3[i] - l3[i]) + (r2[i] - l2[i]) + (r1[i] - l1[i]) + 3;
    	}
    	sort(Q + 1, Q + 1 + subs, SortWith);
    	for (int i = 1; i <= subs; ++i) {
    		while (r < Q[i].r) MakeCont(++r, 1, bit);
    		while (l > Q[i].l) MakeCont(--l, 1, bit);
    		while (r > Q[i].r) MakeCont(r--, -1, bit);
    		while (l < Q[i].l) MakeCont(l++, -1, bit);
    		if (!vis[Q[i].id - fr + 1]) {
    			vis[Q[i].id - fr + 1] = 1;
    			S[Q[i].id - fr + 1] = bit;
    		} else {
    			S[Q[i].id - fr + 1] &= bit;
    		}
    	}
    	for (int i = fr; i <= ba; ++i)
    		ans[i] -= S[i - fr + 1].count() * 3;
    }
    
    signed main() {
    	scanf("%d %d", &n, &m);
    	block = sqrt(n);
    	for (int i = 1; i <= n; ++i) {
    		scanf("%d", &origin[i]);
    		appear[i] = (i - 1) / block + 1;
    		disc.push_back(origin[i]);
    	}
    	sort(disc.begin(), disc.end());
    	for (int i = 1; i <= n; ++i)
    		origin[i] = GetID(origin[i]);
    	for (int i = 1; i <= m; ++i) {
    		scanf("%d %d", &l1[i], &r1[i]);
    		scanf("%d %d", &l2[i], &r2[i]);
    		scanf("%d %d", &l3[i], &r3[i]);
    	}
    	for (int i = 1; i <= m; i += 23333) Contribute(i, min(m, i + 23332));
    	for (int i = 1; i <= m; ++i) printf("%d
    ", ans[i]);
    	return 0;
    }
    
  • 相关阅读:
    初始FreeMake
    C#三层架构
    文件上传
    Jquery动画效果(混合)
    反射机制
    Java使用Sockt进行通信(2)
    Java使用Socket进行通信
    JavaScript基础
    Java的继承
    事物>视图>索引>备份和恢复
  • 原文地址:https://www.cnblogs.com/orchid-any/p/13800987.html
Copyright © 2011-2022 走看看