[做题记录-数据结构] P7446 [Ynoi2007] rfplca

我觉得是个妙妙题但是好像讲课的时候被Qiuls秒掉了qwq。

对序列分块, 然后维护一个\(b_i\)表示第一次跳出块的时候会跳到哪个点。由于祖先只会减小, 所以一个块如果被整体打了超过根号次标记, 就不用重构了, 否则重构。那么一个大小为\(\sqrt n\)的块会重构\(\sqrt n\)次, 每次的操作只会有\(\sqrt n\)的代价, 所以总复杂度也是\(\O(n \sqrt n)\)级别的了。

求lca的时候就像树剖一样跳即可。

#include <bits/stdc++.h>
#include <bits/extc++.h>

using namespace std;
using namespace __gnu_cxx;
using namespace __gnu_pbds;

class Input {
	#define MX 1000000
	private :
		char buf[MX], *p1 = buf, *p2 = buf;
		inline char gc() {
			if(p1 == p2) p2 = (p1 = buf) + fread(buf, 1, MX, stdin);
			return p1 == p2 ? EOF : *(p1 ++);
		}
	public :
		Input() {
			#ifdef Open_File
				freopen("a.in", "r", stdin);
				freopen("a.out", "w", stdout);
			#endif
		}
		template <typename T>
		inline Input& operator >>(T &x) {
			x = 0; int f = 1; char a = gc();
			for(; ! isdigit(a); a = gc()) if(a == '-') f = -1;
			for(; isdigit(a); a = gc()) 
				x = x * 10 + a - '0';
			x *= f;
			return *this;
		}
		inline Input& operator >>(char &ch) {
			while(1) {
				ch = gc();
				if(ch != '\n' && ch != ' ') return *this;
			}
		}
		inline Input& operator >>(char *s) {
			int p = 0;
			while(1) {
				s[p] = gc();
				if(s[p] == '\n' || s[p] == ' ' || s[p] == EOF) break;
				p ++; 
			}
			s[p] = '\0';
			return *this;
		}
	#undef MX
} Fin;

class Output {
	#define MX 1000000
	private :
		char ouf[MX], *p1 = ouf, *p2 = ouf;
		char Of[105], *o1 = Of, *o2 = Of;
		void flush() { fwrite(ouf, 1, p2 - p1, stdout); p2 = p1; }
		inline void pc(char ch) {
			* (p2 ++) = ch;
			if(p2 == p1 + MX) flush();
		}
	public :
		template <typename T> 
		inline Output& operator << (T n) {
			if(n < 0) pc('-'), n = -n;
			if(n == 0) pc('0');
			while(n) *(o1 ++) = (n % 10) ^ 48, n /= 10;
			while(o1 != o2) pc(* (--o1));
			return *this; 
		}
		inline Output & operator << (char ch) {
			pc(ch); return *this; 
		}
		inline Output & operator <<(const char *ch) {
			const char *p = ch;
			while( *p != '\0' ) pc(* p ++);
			return * this;
		}
		~Output() { flush(); } 
	#undef MX
} Fout;

#define cin Fin
#define cout Fout
#define endl '\n'

using LL = long long;

inline int log2(unsigned int x);
inline int popcount(unsigned x);
inline int popcount(unsigned long long x);
template<typename T> struct BinaryQueue;
template<typename T>struct BinaryQueue {
	__gnu_pbds :: priority_queue<T, less<T>, binary_heap_tag> q;
	void push(T x) { q.push(x); }
	void pop() { q.pop(); }
} ;

template <int mod>
class Int {
	private :
		inline int Mod(int x) { return x + ((x >> 31) & mod); } 
		inline int power(int x, int k) {
			int res = 1;
			while(k) {
				if(k & 1) res = 1LL * x * res % mod;
				x = 1LL * x * x % mod; k >>= 1;
			}
			return res;
		}
	public :
		int v;
		Int(int _v = 0) : v(_v) {}
		operator int() { return v; }
		
		inline Int operator =(Int x) { return Int(v = x.v); }
		inline Int operator =(int x) { return Int(v = x); }
		inline Int operator *(Int x) { return Int(1LL * v * x.v % mod); }
		inline Int operator *(int x) { return Int(1LL * v * x % mod); }
		inline Int operator +(Int x) { return Int( Mod(v + x.v - mod) ); }
		inline Int operator +(int x) { return Int( Mod(v + x - mod) ); }
		inline Int operator -(Int x) { return Int( Mod(v - x.v) ); }
		inline Int operator -(int x) { return Int( Mod(v - x) ); }
		inline Int operator ~() { return Int(power(v, mod - 2)); }
		inline Int operator +=(Int x) { return Int(v = Mod(v + x.v - mod)); }
		inline Int operator +=(int x) { return Int(v = Mod(v + x - mod)); }
		inline Int operator -=(Int x) { return Int(v = Mod(v - x.v)); }
		inline Int operator -=(int x) { return Int(v = Mod(v - x)); }
		inline Int operator *=(Int x) { return Int(v = 1LL * v * x.v % mod); }
		inline Int operator *=(int x) { return Int(v = 1LL * v * x % mod); }
		inline Int operator /=(Int x) { return Int(v = v / x.v); }
		inline Int operator /=(int x) { return Int(v = v / x); }
		inline Int operator ^(int k) { return Int(power(v, k)); }
} ;

using mint = Int<30011>;

const int N = 4e5 + 10;

int n, m, blk, B;
int L[N], R[N], bel[N], cnt[N];
int a[N], b[N];
int lj[N];

/*
	b 第一次跳出块以后的祖先是谁
*/

void recalc(int id) {
	for(register int i = L[id]; i <= R[id]; i ++) {
		a[i] = max(a[i] - lj[id], 1);
		b[i] = a[i];
		if(b[i] < L[id]) continue;
		else b[i] = b[a[i]];
	}
	lj[id] = 0;
}

void modify(int x, int y, int v) {
	int l = bel[x]; int r = bel[y];
	if(l == r) {
		for(register int i = x; i <= y; i ++) a[i] = max(a[i] - v, 1);
		recalc(l); return ;
	}
	for(register int i = x; i <= R[l]; i ++) a[i] = max(a[i] - v, 1); recalc(l);
	for(register int i = L[r]; i <= y; i ++) a[i] = max(a[i] - v, 1); recalc(r);
	for(register int i = l + 1; i <= r - 1; i ++) {
		cnt[i] ++; lj[i] += v;
		if(cnt[i] <= B) recalc(i);
	}
}

#define jpb(x) max(1, b[x] - lj[bel[x]])
#define jpa(x) max(1, a[x] - lj[bel[x]])

int lca(int x, int y) {
	while(1) {
		if(bel[x] < bel[y]) swap(x, y);
		if(bel[x] != bel[y]) x = jpb(x);
		else {
			if(jpb(x) != jpb(y)) x = jpb(x), y = jpb(y);
			else break;
		}
	}
	while(x != y) {
		if(x > y) x = jpa(x);
		else y = jpa(y);
	}
	return x;
}

int main() {
	cin >> n >> m;
	for(int i = 2; i <= n; i ++) cin >> a[i];
	B = sqrt(n) + 1;
	for(int i = 1; i <= n; i ++) bel[i] = (i - 1) / B + 1;
	blk = bel[n];
	for(int i = 1; i <= blk; i ++) {
		L[i] = (i - 1) * B + 1;
		R[i] = min(i * B, n);
		recalc(i);
	}
	int lastans = 0;
	while(m --) {
		int opt; cin >> opt;
		if(opt == 1) {
			int l, r, x;
			cin >> l >> r >> x;
			l ^= lastans; r ^= lastans; x ^= lastans;
			modify(l, r, x);
		}
		else {
			int u, v;
			cin >> u >> v;
			u ^= lastans;
			v ^= lastans;
			lastans = lca(u, v);
			cout << lastans << endl;
		}
	}
	return 0;
}

inline int log2(unsigned int x) { return __builtin_ffs(x); }
inline int popcount(unsigned int x) { return __builtin_popcount(x); }
inline int popcount(unsigned long long x) { return __builtin_popcountl(x); }

// Last Year
posted @ 2021-09-15 10:33  HN-wrp  阅读(29)  评论(0编辑  收藏  举报