线段树样例不过求调急!!!悬2关!!!

P4145 上帝造题的七分钟 2 / 花神游历各国

最大只有10^12,开6次方就开不了了,所以直接暴力改 我的代码,有注释,可以参考一下 ~~求关~~ ```cpp #include <iostream> #include <cstdio> #include <cmath> using namespace std; typedef long long ll; const int N = 1e5+10; struct node { int l, r; ll sumn; // 区间和 bool tag; // "开不了方"标记, 初始设为0 }ST[N << 2]; ll a[N]; int n, m; inline void push_up(int ind) { // 维护区间和 ST[ind].sumn = ST[ind*2].sumn+ST[ind*2+1].sumn; // 维护"开不了方"标记,左子区间和右子区间都开不了方, // 它自然也开不了 ST[ind].tag = ST[ind*2].tag && ST[ind*2+1].tag; } inline void build(int ind, int l, int r) // 建树 { ST[ind].l = l; ST[ind].r = r; ST[ind].tag = 0; if(l == r) { ST[ind].sumn = a[l]; return; } int mid = (l+r)>>1; build(ind*2, l, mid); build(ind*2+1, mid+1, r); push_up(ind); } inline void upd(int ind, int tl, int tr) // update函数 { if(ST[ind].tag) return; // 开不了方就没必要搜了 if(tl <= ST[ind].l && ST[ind].r <= tr && ST[ind].l == ST[ind].r) // 搜到要改的单点 { ST[ind].sumn = sqrt(ST[ind].sumn); if(ST[ind].sumn <= 1) ST[ind].tag = 1; // 开不了方了 return; } int mid = (ST[ind].l+ST[ind].r)>>1; if(tl <= mid) upd(ind*2, tl, tr); if(tr > mid) upd(ind*2+1, tl, tr); push_up(ind); } inline ll ask(int ind, int tl, int tr) // 求区间和 { if(tl <= ST[ind].l && ST[ind].r <= tr) return ST[ind].sumn; int mid = (ST[ind].l+ST[ind].r)>>1; ll res = 0; if(tl <= mid) res += ask(ind*2, tl, tr); if(tr > mid) res += ask(ind*2+1, tl, tr); return res; } int main() { // 建议大家在读入 >= 1e5次的数据是用scanf和printf,比cin,cout快很多 cin >> n; for(int i = 1;i <= n;++i) scanf("%lld", &a[i]); build(1, 1, n); cin >> m; int k, l, r; while(m--) { scanf("%d%d%d", &k, &l, &r); if(l > r) swap(l, r); if(k == 0) upd(1, l, r); else printf("%lld\n", ask(1, l, r)); } return 0; } ```
by piano_pei @ 2024-08-07 10:55:01


|