首页 > 其他分享 >[DS记录] 啥都可能有的 DS 复习

[DS记录] 啥都可能有的 DS 复习

时间:2023-03-13 22:55:24浏览次数:45  
标签:cnt 复习 记录 int MAX read rea DS define

莫队

回滚莫队

[Cnoi2019] 数字游戏

当 \([x, y]\) 固定,考虑 \(b_i = [x\le a_i \le y]\)。答案就是 \([l, r]\) 中每一段极长连续 \(1\) 的 \(\sum \dbinom{len + 1}{2}\)

做法是值域上莫队,然后因为是排列,每次一个值域只会修改一个位置的值。考虑 \(0\to 1\) 是好处理的。

维护两个链表 \(pre, suf\),表示极长的包含 \(i\) 的段的开头和结尾。

对于序列分块,记录每个块,不包含开头末尾极长连续段贡献的其他贡献 mid。(如果整个串都是 1, mid[i] = 0)

pre 和 suf 的维护就是每次合并 \(p\) 两端的,然后比较繁琐。

\(1 \to 0\) 非常难,于是考虑回滚莫队撤销怎么做,我们考虑当进行别的操作时,用另一个数组继承原数组的值,然后操作完了,再标记回来,这样做,就不用考虑撤销的问题了。非常牛逼的 std 实现。

点击查看代码
// 僕らタイムフライヤー \
   時を駆け上がるクライマー \
   時のかくれんぼ \
   はぐれっこはもういやなんだ
#include <bits/stdc++.h>
#include <assert.h>
using namespace std;
typedef long long ll;
typedef double db;
#define int long long 
#define ep emplace_back
#define pii pair<int,int>
#define fi first
#define se second
#define mp make_pair
#define fout freopen("out.out","w",stdout);
#define fin freopen("in.in","r",stdin);
#define dd(x) cerr << #x" = " << x << endl;
inline int read() {
	int x=0, v=1,ch=getchar();
	while('0'>ch||ch>'9') {
		if(ch=='-') v=0;
		ch=getchar();
	}while('0'<=ch&&ch<='9') {
		x=(x*10)+(ch^'0');
		ch=getchar();
	}return v?x:-x;
}
const int MAX = 2e5 + 5;

int bl[MAX], L[MAX], R[MAX];
ll bm(int x) { return 1ll * x * (x + 1) / 2; }
template <const int SIZ> 
struct point {
	int rea[SIZ];
	int vit[SIZ]; 
	int t[SIZ];
	int cnt = 1;
	bool fvit = 0;
	
	void Roll() { ++ cnt; }
	void Vit() {fvit = 1, Roll(); }
	void Rea() {fvit = 0; }
	void Clr() { memset(rea, 0, sizeof(rea)); Roll(); }
	
	int &operator [] (int i) {
		if(fvit) {
			if(cnt ^ t[i]) t[i] = cnt, vit[i] = rea[i];
			return vit[i];
		}
		return rea[i];
	}
};

struct Q{
	int l, r, x, y, id;
	Q() {}
	Q(int _id) {
		l = read(), r = read(), x = read(), y = read();
		id = _id;
	}
	bool operator < (const Q & h) const {
		return (bl[x] == bl[h.x] ? y < h.y : x < h.x);
	}
} q[MAX];

int n, T;
int c[MAX];
int pc[MAX];

ll ret[MAX];

point<MAX> pre, nxt, mid;

int bf1(const Q & q) {
	int ans = 0, cnt = 0;
	for(int i = q.l; i <= q.r; ++ i) {
		if(q.x <= c[i] && c[i] <= q.y) {
			++ cnt;
		}else {
//			ans += bm(cnt);
			cnt = 0;
		}
		ans += cnt;
	}
	return ans;
}

int bf2(const Q & q) {
	int ans = 0;
	for(int i = q.x; i <= q.y; ++ i) {
		int p = pc[i];
		if(q.l <= p && p <= q.r) {
			ans -= bm(p - pre[p - 1]);
			ans -= bm(nxt[p + 1] - p);
			nxt[pre[p - 1]] = nxt[p + 1];
			pre[nxt[p + 1]] = pre[p - 1];
			ans += bm(nxt[p + 1] - pre[p - 1] + 1);
		}
	}
	pre.Roll(), nxt.Roll(); 
	return ans;
}

void add(int x) {
	/*
	
	修改时有原则:如果 p 不是块的左右端点,那么以后是不会再被用到的。 
	
	*/
	int p = pc[x], b = bl[p];
	if(p != L[b]) {
		if(pre[p - 1] != L[b]) mid[b] -= bm(p - pre[p - 1]);
		if(p == R[b]) {
			nxt[p] = p;
			pre[p] = pre[p - 1];
			nxt[pre[p - 1]] = p;
		}else {
			nxt[pre[p - 1]] = nxt[p + 1];
			pre[nxt[p + 1]] = pre[p - 1];
		}
	}
	if(p != R[b]) {
		if(nxt[p + 1] != R[b]) mid[b] -= bm(nxt[p + 1] - p);
		if(p == L[b]) {
			pre[p] = p;
			nxt[p] = nxt[p + 1];
			pre[nxt[p + 1]] = p;
		}else {
			nxt[pre[p - 1]] = nxt[p + 1];
			pre[nxt[p + 1]] = pre[p - 1];
		}
	}
	if(p != L[b] && p != R[b] && pre[p - 1] != L[b] && nxt[p + 1] != R[b]) {
		mid[b] += bm(nxt[p + 1] - pre[p - 1] + 1);
	}
}


signed main() {
	n = read(); T = read();
	for(int i = 1; i <= n; ++ i) {
		c[i] = read(); 
		pc[c[i]] = i; 
	}
	int B = n / (sqrt(T * 2 / 3) + 1) + 1; 
	int LIM = (n - 1) / B + 1;
	for(int i = 1; i <= LIM; ++ i) {
		L[i] = R[i - 1] + 1;
		R[i] = R[i - 1] + B; if(R[i] > n) R[i] = n;
		for(int j = L[i]; j <= R[i]; ++ j) bl[j] = i;
	} 
	
	for(int i = 0; i <= n + 1; ++ i) pre[i] = i + 1, nxt[i] = i - 1;
	nxt.Vit(), pre.Vit(), mid.Vit();
	
	int ec = 0;
	for(int i = 1; i <= T; ++ i) {
		Q x = Q(i);
		if(x.r - x.l <= B * 2) ret[i] = bf1(x);
		else if(x.y - x.x <= B * 2) ret[i] = bf2(x);
		else q[++ ec] = x;
	}	
	sort(q + 1, q + 1 + ec);
	int pt = 1;
	for(int t = 1; t < bl[n]; ++ t) {
		int r = R[t];
		nxt.Rea(), pre.Rea(), mid.Rea(); 
		for(int i = 0; i <= n + 1; ++ i) pre[i] = i + 1, nxt[i] = i - 1;
		mid.Clr();
		while(pt <= ec && bl[q[pt].x] == t) {
			const Q & nq = q[pt];
			nxt.Rea(), pre.Rea(), mid.Rea();
			while(r < nq.y) add(++ r);
			
			nxt.Vit(), pre.Vit(), mid.Vit();
			for(int j = nq.x; j <= R[t]; ++ j) 
				add(j);
			
			ll ans = 0, cnt = 0;
			for(int i = nq.l; i <= R[bl[nq.l]]; ++ i) {
				if(nq.x <= c[i] && c[i] <= nq.y) ++ cnt;
				else ans += bm(cnt), cnt = 0;
			}
			for(int i = bl[nq.l] + 1; i < bl[nq.r]; ++ i) {
				if(nxt[L[i]] == R[i]) cnt += R[i] - L[i] + 1; 
				else {
					cnt += nxt[L[i]] - L[i] + 1;
					ans += bm(cnt) + mid[i];
					cnt = R[i] - pre[R[i]] + 1;
				}
			}
			for(int i = L[bl[nq.r]]; i <= nq.r; ++ i) {
				if(nq.x <= c[i] && c[i] <= nq.y) ++ cnt;
				else ans += bm(cnt), cnt = 0;
			}
			
			ans += bm(cnt);
			ret[nq.id] = ans;
			
			nxt.Roll(), pre.Roll(), mid.Roll();
			++ pt; 
		}
	}
	for(int i = 1; i <= T; ++ i) printf("%lld\n", ret[i]);
	return 0;
}

标签:cnt,复习,记录,int,MAX,read,rea,DS,define
From: https://www.cnblogs.com/Lates/p/17208462.html

相关文章

  • #yyds干货盘点#简单的vuex实现
    实现一个vuex插件​​pvuex​​ 初始化:Store声明、install实现,vuex.js:letVue;//定义install方法完成赋值与注册functioninstall(_Vue){Vue=_Vue;Vue.mixin({......
  • #yyds干货盘点#Vuex中的store
    每一个​​Vuex​​应用的核心就是store(仓库)。store基本上就是一个容器,包含着应用中大部分的state(状态)。​​Vuex​​和单纯的全局对象有以下两点不同:​​Vuex​​ 的状态......
  • 【记录】ubuntu20.04配置libvirtd远程认证
    ubuntu20.04配置libvirtd远程认证前置条件:安装virt-managersals2-bin配置/etc/libvirt/libvirtd.conf解除以下注释listen_tcp=1tcp_port="16509"listen_addr=......
  • 澄江街道办配置AEE 执法记录仪,打造“智慧支撑+社区治理”新格局
    随着城市化的发展,人口不断向城市聚集,管理工作环境日渐复杂。为进一步提高街道办管理执法效率,规范街道办管理执法行为,澄江街道办为一线管理人员配置了AEEDSJ-K5高清红外现场......
  • Trino Master OOM 排查记录
    背景最近线上的trino集群master节点老是因为OOMcrash,我们注意到trinocrash前集群正在运行的查询数量正常,不太像是因为并发查询数据太多导致的OOM。遂配置trino......
  • 分页记录处理
    publicIPagerunPageSqlTF(Pagepage,StringsqlStr){ IPagedataList=baseMapper.runPageSql(page,sqlStr); //返回数据 List<HashMap>queryResultList=n......
  • Linux-等保加固-记录用户的登录和操作日志
    通过脚本代码实现记录所有用户的登录操作日志,防止出现安全事件后无据可查修改/etc/profile配置文件,在配置文件中新增以下内容 vi/etc/profileihistoryUSER=`whoam......
  • 记录两个题
    用哈希(散列)方法处理冲突(碰撞)时可能出现堆积(聚集)现象,下列选项中,会受堆积现象直接影响的是()A存储效率B数列函数C装填(装载)因子D平均查找长度正确答案:DD.聚集比......
  • Adobe Substance 3D Designer(Ds 三维贴图材质制作)mac/win
    Substance3DDesigner是一款用于创建3D材质的软件,它可以帮助用户快速创建高质量的3D材质,并且支持多种导出格式,比如说OBJ、FBX、GLTF等。Substance3DDesigner具有强大的......
  • Python3爬虫教程之ADSL拨号爬虫ip池的使用
    在我之前做爬虫经常需要维护自己的爬虫ip池,他可以挑选出很多有用的爬虫地址,因为不是专业的而且这些爬虫ip通常是公共爬虫ip,所以可用率不是太高,而且这样类型的地址很大情况下......