链接:https://ac.nowcoder.com/acm/contest/892/D
题意:
给你一个长度为n的序列,初始为1,2,3...n,对其进行m次操作。 操作有两种: 1 l r 表示将区间[l,r]用 [1,2...r-l+1] 覆盖 2 l r 查询[l,r]的区间和思路:
线段树
比赛时思路对的,但是代码写的太乱,没改出来,赛后重写。
Lazy我开二维数组,记录子节点左右对应的范围。
其他的就根普通线段树一样。
代码:
#include <bits/stdc++.h> using namespace std; typedef long long LL; const int MAXN = 1e5+10; LL Seg[MAXN*4]; LL Lazy[MAXN*4][2]; int n, m; void PushUp(int root) { Seg[root] = Seg[root<<1]+Seg[root<<1|1]; } void PushDown(int root) { if (Lazy[root][1] != 0) { LL lenl = Lazy[root][0]; LL lenr = Lazy[root][1]; LL lenmid = (lenl+lenr)/2; Seg[root<<1] = (lenl+lenmid)*(lenmid-lenl+1)/2; Seg[root<<1|1] = (lenmid+1+lenr)*(lenr-lenmid)/2; Lazy[root<<1][0] = lenl; Lazy[root<<1][1] = lenmid; Lazy[root<<1|1][0] = lenmid+1; Lazy[root<<1|1][1] = lenr; Lazy[root][0] = Lazy[root][1] = 0; } } void Build(int root, int l, int r) { if (l == r) { Seg[root] = l; return; } int mid = (l+r)/2; Build(root<<1, l, mid); Build(root<<1|1, mid+1, r); PushUp(root); } void Update(int root, int l, int r, int ql, int qr) { if (r < ql || qr < l) return; if (ql <= l && r <= qr) { LL lenl = l-ql+1, lenr = r-ql+1; Seg[root] = (lenl+lenr)*(r-l+1)/2; Lazy[root][0] = lenl; Lazy[root][1] = lenr; return; } PushDown(root); int mid = (l+r)/2; Update(root<<1, l, mid, ql, qr); Update(root<<1|1, mid+1, r, ql, qr); PushUp(root); } LL Query(int root, int l, int r, int ql, int qr) { if (r < ql || qr < l) return 0LL; if (ql <= l && r <= qr) return Seg[root]; PushDown(root); LL res = 0; int mid = (l+r)/2; res += Query(root<<1, l, mid, ql, qr); res += Query(root<<1|1, mid+1, r, ql, qr); return res; } int main() { int op, l, r; cin >> n >> m; Build(1, 1, n); while (m--) { cin >> op >> l >> r; if (op == 1) Update(1, 1, n, l, r); else cout << Query(1, 1, n, l, r) << endl; } return 0; }