码迷,mamicode.com
首页 > 其他好文 > 详细

P5385 [Cnoi2019]须臾幻境 / #3514. Codechef MARCH14 GERALD07加强版 [LCT + 主席树]

时间:2020-05-02 18:58:48      阅读:62      评论:0      收藏:0      [点我收藏+]

标签:his   mat   read   this   dig   amp   pen   operator   数组   

如果没有强制在线,那么可以树状数组+扫描线。

我们分析一下,如果有 \(x\) 条有作用的边,那么很显然是 \(n - x\) 个连通块。

如果它是第一条边,也就是上一条边是 0,那么显然可以加入我们的这个答案。
如果和它重复的那条边在 0 ~ l-1 那么很显然也可以加入答案对吧,因为你这条边是连上的了。

所以主席树一下就可以了。
两题的在线方式不同,注意一下。(

// by Isaunoya
#pragma GCC optimize(3)
#include<bits/stdc++.h>
using namespace std;
struct io {
	char buf[1 << 23 | 3], *s;
	int f;
	io() { f = 0, buf[fread(s = buf, 1, 1 << 23, stdin)] = ‘\n‘; }
	io& operator >> (int&x) {
		for(x = f = 0; !isdigit(*s); ++s) f |= *s  == ‘-‘;
		while(isdigit(*s)) x = x * 10 + (*s++ ^ 48);
		return x = f ? -x : x, *this;
	}
};

const int maxn = 4e5 + 54;
int U[maxn], V[maxn], fuck[maxn];
struct lct {
	int ch[maxn][2], fa[maxn], mn[maxn], val[maxn];
	bool rev[maxn];
	lct(){ memset(val, 0x3f, sizeof(val)); }
#define ls(x) ch[x][0]
#define rs(x) ch[x][1]
	bool isroot(int x) { return ls(fa[x]) != x && rs(fa[x]) != x; }
	bool getr(int x) { return rs(fa[x]) == x; }
	void up(int x) {
		mn[x] = x;
		if(val[mn[x]] > val[mn[ls(x)]]) mn[x] = mn[ls(x)];
		if(val[mn[x]] > val[mn[rs(x)]]) mn[x] = mn[rs(x)];
	}
	void pr(int x) { swap(ls(x), rs(x)), rev[x] ^= 1; }
	void down(int x) {
		if(! rev[x]) return;
		if(ls(x)) pr(ls(x));
		if(rs(x)) pr(rs(x));
		rev[x] = 0;
	}
	void pushall(int x) {
		if(! isroot(x)) pushall(fa[x]);
		down(x);
	}
	void rtt(int x) {
		int y = fa[x], z = fa[y], k = getr(x), w = ch[x][k ^ 1];
		if(!isroot(y)) ch[z][getr(y)] = x;
		fa[fa[fa[ch[ch[x][k ^ 1] = y][k] = w] = y] = x] = z, up(y), up(x);
	}
	void splay(int x) {
		pushall(x);
		while(!isroot(x)) {
			int y = fa[x];
			if(!isroot(y)) { rtt(getr(x) ^ getr(y) ? x : y); }
			rtt(x);
		}
	}
	int frt(int x) { acs(x); splay(x); while(ls(x)) down(x), x = ls(x), splay(x); return x; }
	void acs(int x) { for(int tp = 0; x; x = fa[tp = x]) splay(x), rs(x) = tp, up(x); }
	void mrt(int x) { acs(x), splay(x), pr(x); }
	void link(int x, int y) {	mrt(x); if(frt(y) != x) fa[x] = y; }
	void cut(int x, int y) { mrt(x); if(frt(y) == x && fa[y] == x && !ls(y)) fa[y] = ls(x) = 0, up(x); }
	int qry(int x, int y) { mrt(x); acs(y); splay(y); return mn[y]; }
} lct;

int ls[maxn << 6], rs[maxn << 6], sum[maxn << 6], rt[maxn], cnt = 0;

void upd(int &p, int pre, int l, int r, int v) {
	sum[p = ++ cnt] = sum[pre] + 1;
	ls[p] = ls[pre], rs[p] = rs[pre];
	if(l == r) return;
	int mid = l + r >> 1;
	if(v <= mid)
		upd(ls[p], ls[pre], l, mid, v);
	else
		upd(rs[p], rs[pre], mid + 1, r, v);
}

int qry(int ql, int qr , int a , int b , int l, int r) {
	if(ql <= l && r <= qr) { return sum[b] - sum[a]; }
	int mid = l + r >> 1, ans = 0 ;
	if(ql <= mid)
		ans += qry(ql, qr, ls[a], ls[b], l, mid);
	if(qr > mid)
		ans += qry(ql, qr, rs[a], rs[b], mid + 1, r);
	return ans;
}

int n, m, q, type;
signed main() {
#ifdef LOCAL
	freopen("testdata.in", "r", stdin);
#endif
	io in;
	in >> n >> m >> q >> type;
	int tot = n;
	for(int i = 1 ; i <= m ; i ++) {
		int u, v;
		in >> u >> v; U[i] = u; V[i] = v;
		if(u == v) { fuck[i] = i; continue; }
		if(lct.frt(u) == lct.frt(v)) {
			int t = lct.qry(u, v); fuck[i] = lct.val[t];
			lct.cut(U[fuck[i]], t); lct.cut(V[fuck[i]], t);
		}
		++ tot;
		lct.mn[tot] = tot; lct.val[tot] = i;
		lct.link(u, tot); lct.link(v, tot);
	}
	for(int i = 1 ; i <= m ; i ++) upd(rt[i], rt[i - 1], 0, m, fuck[i]);
	int lasans = 0;
	while(q --) {
		int l, r; in >> l >> r;
		if(type) l = (l + lasans) % m + 1,r = (r + lasans) % m + 1;
		if(l > r) swap(l, r);
		lasans = n - qry(0, l - 1, rt[l - 1], rt[r], 0, m);
		cout << lasans << ‘\n‘;
	}
	return 0;
}

P5385 [Cnoi2019]须臾幻境 / #3514. Codechef MARCH14 GERALD07加强版 [LCT + 主席树]

标签:his   mat   read   this   dig   amp   pen   operator   数组   

原文地址:https://www.cnblogs.com/Isaunoya/p/12818898.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!