[做题记录-数据结构][Ynoi 2013 文化课]

赋值操作可以使得把区间视作多项式实现快速求值。

操作符推平使用区间和以及区间乘积实现快速求值。

剩下的注意计算多项式幂次的时候递推计算减少\(\log\), 剩下的是暴力了。

下面是一份由于没有优化新建空间的过不去代码。

#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() {
			//#define Open_File
			#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;// cerr << k;
				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<(int) (1e9 + 7)>;

const int N = 1e5 + 5;

struct Poly {
	vector<int> pol;
	vector<mint> val;
	int sz;
	Poly(int _sz = 0) {
		sz = _sz;
		//while(val.size() < sz) val.emplace_back(0);
		//while(pol.size() < sz) pol.emplace_back(0);
		val.resize(sz); //cerr << sz << endl;
		pol.resize(sz);
	}
	void resize(int _sz) {
		//vector<int> x;
		//vector<mint> y;
		//swap(val, y); swap(pol, x);
		//val.clear();
		//pol.clear();
		sz = _sz;
		val.resize(sz); //cerr << sz << endl;
		pol.resize(sz);
	}
	void del(int pos) {
		int p = lower_bound(pol.begin(), pol.end(), pos) - pol.begin();
		val[p] -= 1;
	}
	void ins(int pos, int v = 1) {
		int l = 0, r = pol.size() - 1, p = r + 1;
		while(l <= r) {
			int mid = (l + r) >> 1;
			if(pol[mid] >= pos) r = mid - 1, p = mid;
			else l = mid + 1;
		}
		//int p = lower_bound(pol.begin(), pol.end(), pos) - pol.begin();
		if(p < pol.size() && pol[p] == pos) val[p] += v;
		else {
			//cerr << pol.size() << ' ';
			//int d = pol.size();
			pol.insert(pol.begin() + p, pos); //cerr << pos << endl;
			val.insert(val.begin() + p, v);
			//d -= pol.size(); 
			//assert(d == -1);
			//assert(sz + 1 == pol.size());
		//	cerr << d << endl;
		//	cerr << (sz + 1) << ' ' << pol.size() << endl;
		//	sz = pol.size();
			sz ++; 
			//assert(sz == pol.size());
			//cerr << sz << ' ' << pol.size() << endl;
		//cerr << pol.size() << endl;
		}
	}
	#define mod 1000000007
	mint query(mint v) {
		mint ans = 0, d = 1;
		int lst = 0;
		for(int i = 0; i < sz; i ++) {
			int k = pol[i] - lst;
			mint x = v;
			while(k) {
				if(k & 1) d *= x;
				x *= x; k >>= 1;
			}
			//d *= v ^ (pol[i] - lst);
			ans += d * val[i];
			lst = pol[i];
		}
		return ans;
	}
	void clear() {
		pol.clear(); val.clear();
	}
} ;

inline void poly_merge(const Poly &a, const Poly &b, Poly &c) {
	static mint val[N];
	static int pol[N];
	int i = 0, j = 0, k = -1;
	while(i < a.sz || j < b.sz) {
		//assert(i < a.sz || j < b.sz);
		if(i < a.sz && (j >= b.sz || (a.pol[i] <= b.pol[j]))) {
			if(k < 0 || pol[k] < a.pol[i]) {
				pol[++ k] = a.pol[i];
				val[k] = a.val[i];
			} 
			else val[k] += a.val[i];
			i ++;
		} 
		else {
			if(k < 0 || pol[k] < b.pol[j]) {
				pol[++ k] = b.pol[j];
				val[k] = b.val[j];
			}
			else val[k] += b.val[j];
			j ++;
		}
		//cerr <<i;
	}
	c.resize(k + 1);
	for(int i = 0; i <= k; i ++) c.val[i] = val[i], c.pol[i] = pol[i];
	//cerr << c.sz << ' ' << c.val.size() << endl;

} 

inline Poly operator +(const Poly &a, const Poly &b) {
	static mint val[N];
	static int pol[N];
	int i = 0, j = 0, k = -1;
	while(i < a.sz || j < b.sz) {
		//assert(i < a.sz || j < b.sz);
		if(i < a.sz && (j >= b.sz || (a.pol[i] <= b.pol[j]))) {
			if(k < 0 || pol[k] < a.pol[i]) {
				pol[++ k] = a.pol[i];
				val[k] = a.val[i];
			} 
			else val[k] += a.val[i];
			i ++;
		} 
		else {
			if(k < 0 || pol[k] < b.pol[j]) {
				pol[++ k] = b.pol[j];
				val[k] = b.val[j];
			}
			else val[k] += b.val[j];
			j ++;
		}
		//cerr <<i;
	}
	Poly c(k + 1);
	for(int i = 0; i <= k; i ++) c.val[i] = val[i], c.pol[i] = pol[i];
	//cerr << c.sz << ' ' << c.val.size() << endl;
	//for(int i = 0; i <= k; i ++) {
	//	cerr << c.pol[i] << endl;
	//}
	return c;
} 

#define ls(x) (x << 1)
#define rs(x) (x << 1 | 1)

int n, m;

struct Node {
	Poly sum_poly; int left_poly, right_poly;
	mint cj, sum, left_cj, right_cj, res;
	int midopt, left_val, right_val;
	int val_tg, opt_tg, len;
} t[N << 2];

int val_seq[N];
int opt_seq[N];

inline Node merge(Node &Left, Node &Right, int midopt) {
	Node Merge; //return Merge;
	Merge.cj = Left.cj * Right.cj;
	Merge.sum = Left.sum + Right.sum;
	Merge.left_val = Left.left_val;
	Merge.right_val = Right.right_val;
	if(midopt == 0) {
		poly_merge(Left.sum_poly, Right.sum_poly, Merge.sum_poly);
	//	Merge.sum_poly = Left.sum_poly + Right.sum_poly;
		Merge.left_poly = Left.left_poly;
		Merge.right_poly = Right.right_poly;
		Merge.left_cj = Left.left_cj;
		Merge.right_cj = Right.right_cj;
		Merge.res = Left.res + Right.res;
	}
	else {
		poly_merge(Left.sum_poly, Right.sum_poly, Merge.sum_poly);
		//Merge.sum_poly = Left.sum_poly + Right.sum_poly;
		Merge.sum_poly.del(Left.right_poly);
		Merge.sum_poly.del(Right.left_poly);
		Merge.sum_poly.ins(Left.right_poly + Right.left_poly, 1);
		Merge.left_poly = (Left.left_poly == Left.len ? Left.len + Right.left_poly : Left.left_poly);
		Merge.right_poly = (Right.right_poly == Right.len ? Right.len + Left.right_poly : Right.right_poly);
		Merge.res = (Left.res - Left.right_cj) + (Right.res - Right.left_cj);
		Merge.res += Left.right_cj * Right.left_cj;
		Merge.left_cj = (Left.left_poly == Left.len ? Left.cj * Right.left_cj : Left.left_cj);
		Merge.right_cj = (Right.right_poly == Right.len ? Right.cj * Left.right_cj : Right.right_cj);
	}
	return Merge;
}

void update(int x) {
	/*
		int midopt, left_val, right_val;
		int val_tg, opt_tg, len;

	*/
	int midopt = t[x].midopt;
	int val_tg = t[x].val_tg;
	int opt_tg = t[x].opt_tg;
	int len = t[x].len;
	t[x] = merge(t[ls(x)], t[rs(x)], midopt);
	t[x].midopt = midopt;
	t[x].val_tg = val_tg;
	t[x].opt_tg = opt_tg;
	t[x].len = len;
	//cerr << x << ' ' << t[x].res << endl;
}

void pushdown_val(int x, mint v) {
	t[x].val_tg = v;
	//cerr << t[x].left_poly << endl;
	//cerr << t[x].right_poly << endl;
	//cerr << t[x].len << endl;
	t[x].left_cj = v ^ t[x].left_poly;
	t[x].right_cj = v ^ t[x].right_poly;
	t[x].cj = v ^ t[x].len;
	t[x].sum = v * t[x].len;
	//cerr << t[x].left_poly << endl;
	//cerr << t[x].right_poly << endl;
	//cerr << v << endl;
	t[x].res = t[x].sum_poly.query(v);
	//cerr << t[x].res << endl;
	t[x].left_val = v;
	t[x].right_val = v;
}

void pushdown_opt(int x, int opt) { //cerr << x << endl;
	if(t[x].len == 1) return ;
	t[x].opt_tg = opt;
	t[x].midopt = opt;
	if(opt == 0) {
		t[x].sum_poly.clear();
		t[x].sum_poly.sz = 0;
		t[x].sum_poly.ins(1, t[x].len);
		t[x].left_poly = t[x].right_poly = 1;
		t[x].res = t[x].sum;
		t[x].left_cj = t[x].left_val;
		t[x].right_cj = t[x].right_val;
	}
	else {
		t[x].sum_poly.clear(); //cerr << t[x].sum_poly.val.size() << endl;
		t[x].sum_poly.sz = 0;
		t[x].sum_poly.ins(t[x].len, 1);
		//cerr << t[x].sum_poly.val.size() << endl;
		t[x].left_poly = t[x].right_poly = t[x].len;
		t[x].res = t[x].cj;
		t[x].left_cj = t[x].cj;
		t[x].right_cj = t[x].cj;
	}
}

void pushdown(int x) {
	if(t[x].opt_tg != -1) {
		pushdown_opt(ls(x), t[x].opt_tg);
		pushdown_opt(rs(x), t[x].opt_tg);
		t[x].opt_tg = -1;
	}
	if(t[x].val_tg != 0) {
		pushdown_val(ls(x), t[x].val_tg);
		pushdown_val(rs(x), t[x].val_tg);
		t[x].val_tg = 0;
	}
}

void build(int x, int l, int r) { //cerr << x << ' ' << l << ' ' << r << endl;
	t[x].val_tg = 0;
	t[x].opt_tg = -1;
	t[x].len = r - l + 1;
//	cerr << x << ' ' << l << ' ' << r << endl;
//	cerr << x << ' ' << t[x].opt_tg << endl;
	if(l == r) {
		Poly tmp(1);
		tmp.pol[0] = 1;
		tmp.val[0] = 1;
		t[x].sum_poly = tmp;
		t[x].left_poly = t[x].right_poly = 1;
		t[x].cj = t[x].sum = t[x].left_cj = t[x].right_cj = t[x].res = val_seq[l];
		t[x].left_val = val_seq[l];
		t[x].right_val = val_seq[l];
		//cerr << x << ' ' << l << ' ' << r << ' ' << t[x].res << endl;
		return ;
	}
	int mid = (l + r) >> 1;
	t[x].midopt = opt_seq[mid];
	//cerr << mid << endl;
	//if(x == 4) cerr << opt_seq[mid] << endl;
	build(ls(x), l, mid); build(rs(x), mid + 1, r);
	update(x);
//	cerr << x << ' ' << l << ' ' << r << ' ' << t[x].res << ' ' << t[x].midopt << endl;
}

void Modify_Val(int x, int l, int r, int L, int R, int val) { //cerr << x << endl;
	
	if(L <= l && r <= R) {
		pushdown_val(x, val); return ;
	}
	//cerr << t[x].opt_tg << endl;
	pushdown(x); //cerr << l << ' ' << r << ' ' << L << ' ' << R << endl;
	int mid = (l + r) >> 1;
	if(L <= mid) Modify_Val(ls(x), l, mid, L, R, val);
	if(R > mid) Modify_Val(rs(x), mid + 1, r, L, R, val);
	update(x);
}

void Modify_Opt(int x, int l, int r, int L, int R, int opt) {
	if(r - l + 1 <= 1) return ;
	if(L <= l && r <= R) {
		//cerr << x << ' ' << l << ' ' << r << endl;
		pushdown_opt(x, opt); return ;
	}
	pushdown(x);
	int mid = (l + r) >> 1;
	if(L <= mid && R >= mid) t[x].midopt = opt;
	if(L <= mid) Modify_Opt(ls(x), l, mid, L, R, opt);
	if(R > mid) Modify_Opt(rs(x), mid + 1, r, L, R, opt);
	update(x);
}

Node Query(int x, int l, int r, int L, int R) { //cerr << x << endl;
	if(L <= l && r <= R) return t[x];
	pushdown(x);
	int mid = (l + r) >> 1;
	if(L > mid) return Query(rs(x), mid + 1, r, L, R);
	if(R <= mid) return Query(ls(x), l, mid, L, R);
	Node lps, rps;
	lps = Query(ls(x), l, mid, L, R);
	rps = Query(rs(x), mid + 1, r, L, R);
//	cerr << t[x].midopt << endl;
//	cerr << lps.res << ' ' << rps.res << endl;
	return merge(lps, rps, t[x].midopt);
}

int main() {
	cin >> n >> m;
	for(int i = 1; i <= n; i ++) {
		unsigned int v;
		cin >> v;
		v %= (unsigned int) (1e9 + 7);
		val_seq[i] = v;
		//val_seq[i] %= (int) (1e9 + 7);
	}
	for(int i = 1; i <  n; i ++) cin >> opt_seq[i];
	build(1, 1, n); //return 0;
	//cout << t[1].res << endl; return 0;
	while(m --) {
		int op, l, r;
		cin >> op >> l >> r; //cerr << op << endl;
		if(op == 1) {
			unsigned int x; cin >> x; x %= (unsigned int) (1e9 + 7);
			Modify_Val(1, 1, n, l, r, x);
		}
		if(op == 2) {
			unsigned int x; cin >> x; x %= (unsigned int) (1e9 + 7);
			Modify_Opt(1, 1, n, l, r, x);
		}
		if(op == 3) {
			Node tmp = Query(1, 1, n, l, r);
			cout << tmp.res << 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-05 14:26  HN-wrp  阅读(34)  评论(1编辑  收藏  举报