CSP认证2020_12_5_星际旅行

学习

Posted by simplex on April 5, 2021

CSP认证2020_12_5_星际旅行

线段树,然后发现可以用cnt计数,来减少内存占用,原本我还在纳闷,1e9这怎么可能行,看了别人的博客,哇,原来可以这么做,于是自己实现了一下,还偷了一手人家的数据范围嘻嘻

从数据范围里面,我学到了单个数组下标不能爆int,总之很大的一题,花了2天彻底100了,拉稀般畅爽

// author: M@
#define m_
//#define _DEBUG_
#include<iostream>
#include<cstdio>
#include<string.h>
#include<iomanip>
#include<queue>
#include<vector>
#include<map>
#include<algorithm>
#include<cmath>
#include<list>
#include<set>
#include<string>
#define clr(a)   memset((a),0,sizeof (a))
//#define li idx<<1
//#define ri idx<<1|1

using namespace std;
typedef unsigned int ui;
typedef long long LL;
typedef pair<int,int> pii;
//const int INF=0x3f3f3f3f;
const int INF = 1e9;
const LL LINF=1e18;
const double DINF=1e9;
const double EPS=1e-9;
const int maxn= 1e7 + 5;
const int maxm = 5e4 + 5;
const int mod = 1000000007;
int n, m;
int op, l, r, a, b, c;
int tree[maxn][3];
int add[maxn][3];
int mul[maxn];
int ls[maxn], rs[maxn];
int trans[maxn];
LL x, y, z;
int cnt = 1;


void sswap(int &a, int &b, int &c){
	swap(a, c);
	swap(a, b);
}

//void build(int idx, int l, int r){
//	mul[idx] = 1;
//	if(l == r){
//		return ;
//	}
//	int mid = (l + r) / 2;
//	build(li, l, mid);
//	build(ri, mid + 1, r);
//}

void pushDown(int idx, int l, int r){
	int li = ls[idx], ri = rs[idx];
	if(!ls[idx]){
		ls[idx] = li = ++cnt;
		mul[cnt] = 1;
	}	
	if(!rs[idx]){
		rs[idx] = ri = ++cnt;
		mul[cnt] = 1;
	}
	LL len = r - l + 1;
	if(len == 1)return;
	for(int i = 0; i < trans[idx]; i++){
		sswap(tree[li][0], tree[li][1], tree[li][2]);
		sswap(tree[ri][0], tree[ri][1], tree[ri][2]);
		sswap(add[li][0], add[li][1], add[li][2]);
		sswap(add[ri][0], add[ri][1], add[ri][2]);
		
	}
	for(int i = 0; i < 3; i++){
		LL temp = LL(mul[idx]) * LL(tree[li][i] ) % mod;
		tree[li][i] = (temp + add[idx][i] * (len - len / 2) % mod) % mod;
		temp = LL(mul[idx]) * LL(tree[ri][i] ) % mod;
		tree[ri][i] = (temp + add[idx][i] * (len / 2) % mod) % mod;
	}
	mul[li] = (LL)mul[li] * mul[idx] % mod;
	mul[ri] = (LL)mul[ri] * mul[idx] % mod;
	trans[li] = (trans[idx] + trans[li]) % 3;
	trans[ri] = (trans[idx] + trans[ri]) % 3;
	for(int i = 0; i < 3; i++){
		add[li][i] = (add[idx][i] + (LL)add[li][i] * mul[idx] % mod) % mod;
		add[ri][i] = (add[idx][i] + (LL)add[ri][i] * mul[idx] % mod) % mod;
		add[idx][i] = 0;
	}
	mul[idx] = 1;
	trans[idx] = 0;
}

void pullUp(int idx){
	int li = ls[idx], ri = rs[idx];
	if(!ls[idx]){
		ls[idx] = li = ++cnt;
		mul[cnt] = 1;
	}	
	if(!rs[idx]){
		rs[idx] = ri = ++cnt;
		mul[cnt] = 1;
	}
	for(int i = 0; i < 3; i++){
		tree[idx][i] = (tree[li][i] + tree[ri][i]) % mod;
	}
}

void up1(int idx, int l, int r, int tl, int tr){// add 
	int li = ls[idx], ri = rs[idx];
	if(!ls[idx]){
		ls[idx] = li = ++cnt;
		mul[cnt] = 1;
	}	
	if(!rs[idx]){
		rs[idx] = ri = ++cnt;
		mul[cnt] = 1;
	}
	LL len = r - l + 1;
	if(l == tl && r == tr){
		add[idx][0] = (add[idx][0] + a) % mod;
		add[idx][1] = (add[idx][1] + b) % mod;
		add[idx][2] = (add[idx][2] + c) % mod;
		tree[idx][0] = (tree[idx][0] + (len * a) % mod) % mod;	
		tree[idx][1] = (tree[idx][1] + (len * b) % mod) % mod;	
		tree[idx][2] = (tree[idx][2] + (len * c) % mod) % mod;	
		return ;
	}
	pushDown(idx, l, r);
	int mid = (l + r) / 2;
	if(mid >= tl)up1(li, l, mid, tl, min(mid, tr));
	if(mid < tr)up1(ri, mid + 1, r, max(mid + 1, tl), tr);
	pullUp(idx);
}

void up2(int idx, int l, int r, int tl, int tr){// add 
	int li = ls[idx], ri = rs[idx];
	if(!ls[idx]){
		ls[idx] = li = ++cnt;
		mul[cnt] = 1;
	}	
	if(!rs[idx]){
		rs[idx] = ri = ++cnt;
		mul[cnt] = 1;
	}
	LL len = r - l + 1;
	if(l == tl && r == tr){
		add[idx][0] = ((LL)add[idx][0] * a) % mod;
		add[idx][1] = ((LL)add[idx][1] * a) % mod;
		add[idx][2] = ((LL)add[idx][2] * a) % mod;
		mul[idx] = (LL(mul[idx]) * a) % mod;
		tree[idx][0] = ((LL)tree[idx][0] * a) % mod;	
		tree[idx][1] = ((LL)tree[idx][1] * a) % mod;	
		tree[idx][2] = ((LL)tree[idx][2] * a) % mod;
//		printf("2 tree[%d] [%d] [%d] [%d] %d %d %d %d mul %d\n", idx, tree[idx][0], tree[idx][1], tree[idx][2], l, r, tl, tr, mul[idx]);
		return;
	}
	pushDown(idx, l, r);
	int mid = (l + r) / 2;
	if(mid >= tl)up2(li, l, mid, tl, min(mid, tr));
	if(mid < tr)up2(ri, mid + 1, r, max(mid + 1, tl), tr);
	pullUp(idx);
//	printf("tree[%d] [%d] [%d] [%d] %d %d %d %d\n", idx, tree[idx][0], tree[idx][1], tree[idx][2], l, r, tl, tr);
}

void up3(int idx, int l, int r, int tl, int tr){// add 
	int li = ls[idx], ri = rs[idx];
	if(!ls[idx]){
		ls[idx] = li = ++cnt;
		mul[cnt] = 1;
	}	
	if(!rs[idx]){
		rs[idx] = ri = ++cnt;
		mul[cnt] = 1;
	}
	LL len = r - l + 1;
	if(l == tl && r == tr){
		sswap(tree[idx][0], tree[idx][1], tree[idx][2]);
		sswap(add[idx][0], add[idx][1], add[idx][2]);
		trans[idx] = (trans[idx] + 1) % 3;
		return ;
	}
	pushDown(idx, l, r);
	int mid = (l + r) / 2;
	if(mid >= tl)up3(li, l, mid, tl, min(mid, tr));
	if(mid < tr)up3(ri, mid + 1, r, max(mid + 1, tl), tr);
	pullUp(idx);
//	printf("tree[%d] [%d] [%d] [%d] %d %d %d %d\n", idx, tree[idx][0], tree[idx][1], tree[idx][2], l, r, tl, tr);
}

void query(int idx, int l, int r, int tl, int tr){
	int li = ls[idx], ri = rs[idx];
	if(!ls[idx]){
		ls[idx] = li = ++cnt;
		mul[cnt] = 1;
	}	
	if(!rs[idx]){
		rs[idx] = ri = ++cnt;
		mul[cnt] = 1;
	}
	if(l == tl && r == tr){
		x = (x + tree[idx][0]) % mod;
		y = (y + tree[idx][1]) % mod;
		z = (z + tree[idx][2]) % mod;
		return ;
	}
	pushDown(idx, l, r);
	int mid = (l + r) / 2;
	if(mid >= tl) query(li, l, mid, tl, min(mid, tr));
	if(mid < tr) query(ri, mid + 1, r, max(mid + 1, tl), tr);
}
int main()
{
#ifdef m_
    freopen("input.txt","r",stdin);
//    freopen("output.txt","w",stdout);
#endif
	scanf("%d%d", &n, &m);
	while(m--){
		int l, r;
		scanf("%d", &op);
		x = y = z = 0;
		switch(op){
			case 1:{
				scanf("%d%d%d%d%d", &l, &r, &a, &b, &c);
				up1(1, 1, n, l, r);
				break;
			}
			case 2:{
				scanf("%d%d%d", &l, &r, &a);
				up2(1, 1, n, l, r);
				break;
			}	
			case 3:{
				scanf("%d%d", &l, &r);
				up3(1, 1, n, l, r);
				break;
			}
			case 4:{
				scanf("%d%d", &l, &r);
				query(1, 1, n, l, r);
				cout<< (x * x % mod + y * y % mod + z * z % mod) % mod <<endl;
				break;
			}	
				
		}
	}
#ifdef m_
    fclose(stdin);
//    fclose(stdout);
#endif
    return 0;
}

甚至想发出线段树不过如此的感叹,不过回想自己写代码的弱智过程,还是算了

总结:自己是菜,不能硬肛题目,该看题解看题解。