zoukankan      html  css  js  c++  java
  • 回滚莫队(不删除莫队)

    AT1219 歴史の研究 - 洛谷

    题意

    查询区间 ([l,r]) 内一个数乘上它在区间出现次数的最大值

    使用莫队的时候进行增加操作的时候会很简单,但是在删除操作的时候不是那么好维护的时候,可以使用不删除的莫队(回滚莫队)

    还是相同的思路,先把询问排序

    然后对于左端点在同一个块的询问来说

    如图

    如果右端点也在块内,则暴力计算

    否则左端点从下一个块的左边开始,右端点单调向右移动。

    左端点在块内反复进行回滚操作。

    这样就在保证时间复杂度还是 (O(nsqrt n)) 的情况下避免了删除操作

    /*
     * @Author: zhl
     * @Date: 2020-11-19 10:38:35
     */
     #include<bits/stdc++.h>
    using namespace std;
    using ll = long long;
    const int N = 1e5 + 10;
    int n, m, len, cnt[N], nums[N], w[N], ID[N];
    ll ans[N];
    struct Query {
    	int id, l, r;
    	bool operator < (const Query& rhs)const {
    		int al = ID[l], bl = ID[rhs.l];
    		if (al != bl)return al < bl;
    		return r < rhs.r;
    	}
    }q[N];
    
    void add(int x, ll& res) {
    	cnt[x]++;
    	res = max(res, 1ll * cnt[x] * nums[x]);
    }
    
    int main() {
    	scanf("%d%d", &n, &m);
    	int numID = 0;
    	for (int i = 1; i <= n; i++)scanf("%d", w + i), nums[++numID] = w[i];
    
    	sort(nums + 1, nums + 1 + n);
    	numID = unique(nums + 1, nums + 1 + n) - nums - 1;
    	len = sqrt(n);
    	for (int i = 1; i <= n; i++)ID[i] = i / len;
    	for (int i = 1; i <= n; i++)w[i] = lower_bound(nums + 1, nums + 1 + numID, w[i]) - nums;
    
    	for (int i = 1; i <= m; i++) {
    		scanf("%d%d", &q[i].l, &q[i].r);
    		q[i].id = i;
    	}
    
    	sort(q + 1, q + 1 + m);
    
    	for (int x = 1; x <= m;) {
    		int y = x;
    		while (y <= m and ID[q[y].l] == ID[q[x].l]) y++;
    
    		//块内暴力
    		int right = len * ID[q[x].l] + len;
    		//int right = len * ID[q[y].l]; 这样不对,y不一定比x大
    		
    		while (x < y and q[x].r <= right - 1) {
    			ll res = 0;
    			for (int i = q[x].l; i <= q[x].r; i++) add(w[i], res);
    			ans[q[x].id] = res;
    			for (int i = q[x].l; i <= q[x].r; i++) cnt[w[i]]--;
    			x++;
    		}
    
    		//块外
    		
    		int l = right, r = right - 1;
    		ll res = 0;
    		while (x < y) {
    			int ql = q[x].l, qr = q[x].r;
    			while (r < qr)add(w[++r], res);
    			ll _res = res;
    			while (l > ql)add(w[--l], res);
    			ans[q[x].id] = res;
    			while (l < right) cnt[w[l++]] --;
    			res = _res;
    			x++;
    		}
    		memset(cnt, 0, sizeof cnt);
    	}
    	for (int i = 1; i <= m; i++)printf("%lld
    ", ans[i]);
    }
    

    P5906 【模板】回滚莫队&不删除莫队 - 洛谷

    给定一个序列,多次询问一段区间 ([l,r]),求区间中相同的数的最远间隔距离

    序列中两个元素的间隔距离指的是两个元素下标差的绝对值

    这个说是模板题,其实上一道题更模板。

    #include<bits/stdc++.h>
    using namespace std;
    
    const int N = 2e5 + 10;
    int w[N], ans[N], n, m, nums[N], ID[N], len;
    int fir[N], last[N];
    int mfir[N], mlast[N], mpos[N], mcnt, vis[N], vscnt;
    struct Query {
    	int id, l, r;
    	bool operator < (const Query& b)const {
    		if (ID[l] != ID[b.l])return ID[l] < ID[b.l];
    		return r < b.r;
    	}
    }q[N];
    
    
    void add(int pos, int val, int& res) {
    	if (!fir[val]) fir[val] = pos;
    	else fir[val] = min(fir[val], pos);
    
    	if (!last[val])last[val] = pos;
    	else last[val] = max(last[val], pos);
    
    	res = max(res, last[val] - fir[val]);
    }
    int main() {
    	scanf("%d", &n);
    	int numID = 0;
    	for (int i = 1; i <= n; i++)scanf("%d", w + i), nums[++numID] = w[i];
    
    	sort(nums + 1, nums + 1 + n);
    	numID = unique(nums + 1, nums + 1 + n) - nums - 1;
    
    	for (int i = 1; i <= n; i++)w[i] = lower_bound(nums + 1, nums + 1 + numID, w[i]) - nums;
    
    	len = sqrt(n);
    	for (int i = 1; i <= n; i++)ID[i] = i / len;
    
    	scanf("%d", &m);
    	for (int i = 1; i <= m; i++) {
    		scanf("%d%d", &q[i].l, &q[i].r); q[i].id = i;
    	}
    
    	sort(q + 1, q + 1 + m);
    
    	for (int x = 1; x <= m;) {
    		int y = x;
    		while (y <= m and ID[q[y].l] == ID[q[x].l])y++;
    		int right = ID[q[x].l] * len + len;
    
    		while (x < y and q[x].r <= right - 1) {
    			int res = 0, mcnt = 0; vscnt++;
    			for (int i = q[x].l; i <= q[x].r; i++) {
    				if (vis[w[i]] != vscnt) {
    					vis[w[i]] = vscnt;
    					mpos[++mcnt] = w[i];
    					mfir[mcnt] = fir[w[i]];
    					mlast[mcnt] = last[w[i]];
    				}
    				add(i, w[i], res);
    			}
    			ans[q[x].id] = res;
    			for (int i = 1; i <= mcnt; i++) {
    				fir[mpos[i]] = mfir[i];
    				last[mpos[i]] = mlast[i];
    			}
    			x++;
    		}
    
    		int l = right, r = right - 1;
    		int res = 0;
    
    		while (x < y) {
    			int ql = q[x].l, qr = q[x].r;
    			while (r < qr)r++, add(r, w[r], res);
    			int _res = res;
    			mcnt = 0; vscnt++;
    			while (l > ql) {
    				l--;
    				if (vis[w[l]] != vscnt) {
    					vis[w[l]] = vscnt;
    					mpos[++mcnt] = w[l];
    					mfir[mcnt] = fir[w[l]];
    					mlast[mcnt] = last[w[l]];
    				}
    				add(l, w[l], res);
    			}
    			ans[q[x].id] = res;
    			for (int i = 1; i <= mcnt; i++) {
    				fir[mpos[i]] = mfir[i];
    				last[mpos[i]] = mlast[i];
    			}
    			l = right; res = _res;
    			x++;
    		}
    		memset(fir, 0, sizeof fir); memset(last, 0, sizeof last);
    	}
    	for (int i = 1; i <= m; i++)printf("%d
    ", ans[i]);
    }
    
    
  • 相关阅读:
    数值分析实验之数值积分法(java 代码)
    Python 数据处理
    Python 网络爬虫
    数据库系统开发——旅游公司机票查询及预订系统
    Python词云生成
    Python库的安装与查看
    Python词频统计
    Python程序设计训练
    Python编程基础训练
    如何在同一Linux服务器上创建多站点
  • 原文地址:https://www.cnblogs.com/sduwh/p/14032407.html
Copyright © 2011-2022 走看看