• [做题记录-数据结构] 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 != '
    ' && ch != ' ') return *this;
    			}
    		}
    		inline Input& operator >>(char *s) {
    			int p = 0;
    			while(1) {
    				s[p] = gc();
    				if(s[p] == '
    ' || s[p] == ' ' || s[p] == EOF) break;
    				p ++; 
    			}
    			s[p] = '';
    			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 != '' ) pc(* p ++);
    			return * this;
    		}
    		~Output() { flush(); } 
    	#undef MX
    } Fout;
    
    #define cin Fin
    #define cout Fout
    #define endl '
    '
    
    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
    
  • 相关阅读:
    Python 工程管理及 virtualenv 的迁移
    Python基础系列讲解——random模块随机数的生成
    Python进阶量化交易场外篇5——标记A股市场涨跌周期
    Python学习案例之视频人脸检测识别
    基于python的Splash基本使用和负载均衡配置
    你所听到的技术原理、技术本质到底是什么?
    BAT大厂面试流程剖析
    基于Python的ModbusTCP客户端实现
    互联网寒冬,Python 程序员如何准备面试
    ES-查询后10000条数据的设置
  • 原文地址:https://www.cnblogs.com/clover4/p/15271166.html
Copyright © 2020-2023  润新知