2023年中国高校计算机大赛-团队程序设计天梯赛(GPLT)上海理工大学校内选拔赛 H 摘苹果
算是比较入门的线段树题了
考虑线段树上维护三个值,sum维护总和,used维护当前结点是否还能进行操作,cnt100维护当前结点里面树上苹果数量少于100的树的数量。
我们可以发现每颗树上最多有1e9颗苹果,我们每次减去他三分之一,估算一下每颗树进行50次(k)以内的操作可以做到苹果数量小于10,每颗树遍历一次是log(n)级别的复杂度,因此总的操作复杂度为n * k * log(n)约为 1e8的时间复杂度。我们每次操作区间的时候,对于能进行操作的区间一直递归到最深,然后每当一颗树上的苹果数量小于100的时候我们就给它的cnt100标记为1,每当一颗树上苹果数量小于10的时候,我们就给它的used标记为true,表示当前结点不能再摘苹果了。然后我们用pushup上传信息即可。
#include <iostream>
#include <cstring>
#include <iomanip>
#include <algorithm>
#include <stack>
#include <queue>
#include <numeric>
#include <cassert>
#include <bitset>
#include <cstdio>
#include <vector>
#include <unordered_set>
#include <cmath>
#include <map>
#include <unordered_map>
#include <set>
#include <deque>
#include <tuple>
#include <array>
#define all(a) a.begin(), a.end()
#define cnt0(x) __builtin_ctz(x)
#define endl '\n'
#define ll long long
#define ull unsigned long long
#define cntone(x) __builtin_popcount(x)
#define db double
#define fs first
#define ls(x) (tr[x].l)
#define rs(x) (tr[x].r)
#define cnt(x) (tr[x].cnt)
#define mx(x) (tr[x].v)
#define se second
#define AC main(void)
#define HYS std::ios::sync_with_stdio(false);std::cin.tie(0);std::cout.tie(0);
typedef std::pair<int, int > PII;
typedef std::pair<int, std::pair<int, int>> PIII;
typedef std::pair<ll, ll> Pll;
typedef std::pair<double, double> PDD;
using ld = double long;
const long double eps = 1e-9;
const int INF = 0x3f3f3f3f;
const int N = 1e5 + 10, M = 4e5 + 10;
int n , m, p;
int d1[] = {0, 0, 1, -1};
int d2[] = {1, -1, 0, 0};
int a[N];
struct node{
int l, r;
ll sum;
int cnt100, used;//小于100的数量,
}tr[N << 2];
inline void pushup(int u){
if(tr[u << 1].used && tr[u << 1 | 1].used) tr[u].used = true;
tr[u].sum = tr[u << 1].sum + tr[u << 1 | 1].sum;
tr[u].cnt100 = tr[u << 1].cnt100 + tr[u << 1 | 1].cnt100;
}
inline void build_tree(int u, int l, int r){
tr[u] = {l, r};
if(l == r){
tr[u].sum = a[l];
if(a[l] < 100) tr[u].cnt100 = 1;
if(a[l] < 10) tr[u].used = true;
return ;
}
int mid = l + r >> 1;
build_tree(u << 1, l, mid);
build_tree(u << 1 | 1, mid + 1, r);
pushup(u);
}
inline void modify(int u, int l, int r){
if(tr[u].used) return ;
if(tr[u].l == tr[u].r){
tr[u].sum -= (tr[u].sum + 2) / 3;
if(tr[u].sum < 100) tr[u].cnt100 = 1;
if(tr[u].sum < 10) tr[u].used = true;
return ;
}
int mid = tr[u].l + tr[u].r >> 1;
if(l <= mid) modify(u << 1, l, r);
if(r > mid) modify(u << 1 | 1, l, r);
pushup(u);
}
inline int query100(int u, int l, int r){
if(tr[u].l >= l && tr[u].r <= r) return tr[u].cnt100;
int res = 0;
int mid = tr[u].l + tr[u].r >> 1;
if(l <= mid) res += query100(u << 1, l, r);
if(r > mid) res += query100(u << 1 | 1, l, r);
return res;
}
inline ll querysum(int u, int l, int r){
if(tr[u].l >= l && tr[u].r <= r) return tr[u].sum;
ll res = 0;
int mid = tr[u].l + tr[u].r >> 1;
if(l <= mid) res += querysum(u << 1, l, r);
if(r > mid) res += querysum(u << 1 | 1, l, r);
return res;
}
inline void solve(){
std::cin >> n >> m;
for(int i = 1; i <= n; i ++) std::cin >> a[i];
build_tree(1, 1, n);
for(int i = 1; i <= m; i ++){
int op, l, r;
std::cin >> op >> l >> r;
if(op == 1){
modify(1, l, r);
}else if(op == 2){
std::cout << query100(1, l, r) << '\n';
}else{
std::cout << querysum(1, l, r) << '\n';
}
}
}
signed AC{
HYS
int _ = 1;
//std::cin >> _;
while(_ --)
solve();
return 0;
}
最后放一道很像的题,也不知道没买牛客集训的能不能写
#include <iostream>
#include <cstring>
#include <iomanip>
#include <algorithm>
#include <stack>
#include <queue>
#include <numeric>
#include <cassert>
#include <bitset>
#include <cstdio>
#include <vector>
#include <unordered_set>
#include <cmath>
#include <map>
#include <unordered_map>
#include <set>
#include <deque>
using namespace std;
#define all(a) a.begin(), a.end()
#define cnt0(x) __builtin_ctz(x)
#define endl '\n'
#define itn int
#define ll long long
#define ull unsigned long long
#define rep(i, a, b) for(int i = a;i <= b; i ++)
#define per(i, a, b) for(int i = a;i >= b; i --)
#define cntone(x) __builtin_popcount(x)
#define db double
#define x first
#define y second
#define AC main(void)
#define HYS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
typedef pair<int, int > PII;
typedef pair<int, pair<int, int>> PIII;
typedef pair<ll, ll> Pll;
typedef pair<double, double> PDD;
using ld = double long;
const int MOD = 998244353;
const double eps = 1e-8;
const int N = 1e3 + 10, M = 1e5 + 10;
const int INF = 0x3f3f3f3f;
int n, m;
int _ = 1;
int res;
int d1[] = {0, 0, 1, -1};
int d2[] = {1, -1, 0, 0};
int a[M];
struct node{
int l, r;
ll v;
ll lazy;
int tar, keep;
}tr[M * 4];
void pushup(int u){
tr[u].v = tr[u << 1].v + tr[u << 1 | 1].v;
if(tr[u << 1].keep && tr[u << 1 | 1].keep) tr[u].keep = 1;
}
void pushdown(int u){
if(tr[u].lazy){
tr[u].tar = 0;
tr[u << 1 | 1].tar = tr[u << 1].tar = 1;
tr[u << 1].lazy += tr[u].lazy;
tr[u << 1 | 1].lazy += tr[u].lazy;
tr[u].lazy = 0;
}
}
int sswr(int x){
double t = sqrt(x);
t *= 10;
int tt = t * 10;
if(tt % 10 >= 5) return (int)t + 1;
else return (int)t;
}
void build_tree(int u, int l, int r){
tr[u] = {l, r};
tr[u].keep = 0;
if(l == r){
tr[u].v = a[l];
return ;
}
int mid = l + r >> 1;
build_tree(u << 1, l, mid);
build_tree(u << 1 | 1, mid + 1, r);
pushup(u);
}
void modify(int u, int l, int r, int k){
if(tr[u].keep) return ;
tr[u].tar = 1;
if(tr[u].l >= l && tr[u].r <= r){
tr[u].lazy += k;
return ;
}
int mid = tr[u].l + tr[u].r >> 1;
if(l <= mid) modify(u << 1, l, r, k);
if(r > mid) modify(u << 1 | 1, l, r, k);
}
ll query(int u, int l, int r){
if(!tr[u].tar || tr[u].keep) return tr[u].v;
tr[u].tar = 0;
if(tr[u].l == tr[u].r){
int last = tr[u].v;
int k = tr[u].lazy;
while(k --){
int now = sswr(last);
if(now == last){
tr[u].keep = 1;
break;
}
last = now;
}
tr[u].lazy = 0;
tr[u].v = last;
return tr[u].v;
}
pushdown(u);
ll sum = 0;
int mid = tr[u].l + tr[u].r >> 1;
sum = query(u << 1, l, r);
sum += query(u << 1 | 1, l, r);
pushup(u);
return sum;
}
void solve(){
cin >> n >> m;
for(int i = 1; i <= n; i ++) cin >> a[i];
build_tree(1, 1, n);
while(m --){
int op;
cin >> op;
if(op == 2) cout << query(1, 1, n) << endl;
else{
int l, r, k;
cin >> l >> r >> k;
modify(1, l, r, k);
}
}
}
int AC{
HYS
//cin >> _;
while(_ --)
solve();
return 0;
}