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;
}
甚至想发出线段树不过如此的感叹,不过回想自己写代码的弱智过程,还是算了
总结:自己是菜,不能硬肛题目,该看题解看题解。