Q - Play With Sequence HDU - 3971 线段树 重新排序建树
Q - Play With Sequence
这个题目是一个线段树,比较特别的线段树,就是c询问一定次数之后重新排序建树来优化减低复杂度。
第一次碰到这种题目有点迷。
这个题目写还是很好写的,就是重新排序建树的位置不太好找。
不过可以知道的是,这是更新花费时间和排序花费时间的一个平衡,这个是一个二次函数,这个二次函数的最低点可以自己测出来。
现在可能有点听不懂,写完代码就很好理解了,
我测的每隔2000次C的操作就重新建树排序是最优的。
800,1000,2200,3000 都是可以的。
#include <cstdio> #include <cstring> #include <cstdlib> #include <algorithm> #include <iostream> #include <queue> #include <string> #include <vector> #include <map> #define inf 0x3f3f3f3f #define inf64 0x3f3f3f3f3f3f3f3f using namespace std; const int maxn = 3e5 + 10; typedef long long ll; ll a[maxn], lc[maxn], rc[maxn], num[maxn]; string s[maxn]; struct node { ll lazy, max, min, len; }tree[maxn*16]; void push_up(int id) { tree[id].max = max(tree[id << 1].max, tree[id << 1 | 1].max); tree[id].min = min(tree[id << 1].min, tree[id << 1 | 1].min); //printf("tree[%d].min=%lld tree[%d].max=%lld\n", id, tree[id].min, id, tree[id].max); } void build(int id,int l,int r) { tree[id].len = r - l + 1; tree[id].lazy = 0; if(l==r) { tree[id].max = tree[id].min = a[l]; return; } int mid = (l + r) >> 1; build(id << 1, l, mid); build(id << 1 | 1, mid + 1, r); push_up(id); } void push_down(int id) { if(tree[id].lazy) { int val = tree[id].lazy; tree[id << 1].max += val; tree[id << 1].min += val; tree[id << 1 | 1].max += val; tree[id << 1 | 1].min += val; tree[id << 1].lazy += val; tree[id << 1 | 1].lazy += val; // printf("tree[%d].max=%lld tree[%d].min=%lld\n", id << 1, tree[id << 1].max, id << 1, tree[id << 1].min); // printf("tree[%d].max=%lld tree[%d].min=%lld\n", id << 1 | 1, tree[id << 1 | 1].max, id << 1 | 1, tree[id << 1 | 1].min); tree[id].lazy = 0; } } void update(int id,int l,int r,ll x,ll y,ll val) { push_down(id); // printf("id=%d l=%d r=%d x=%lld y=%lld val=%lld\n", id, l, r, x, y, val); if(tree[id].min>=x&&tree[id].max<=y) { tree[id].lazy = val; tree[id].min += val; tree[id].max += val; //printf("id=%d min=%lld max=%lld\n", id, tree[id].min, tree[id].max); return; } int mid = (l + r) >> 1; if (tree[id << 1].max >= x && tree[id << 1].min <= y) update(id << 1, l, mid, x, y, val); if (tree[id << 1 | 1].max >= x && tree[id << 1 | 1].min <= y) update(id << 1 | 1, mid + 1, r, x, y, val); push_up(id); } int query(int id,int l,int r,ll x,ll y) { push_down(id); if(tree[id].max<=y&&tree[id].min>=x) { return tree[id].len; } int mid = (l + r) >> 1, ans = 0; if (tree[id << 1].max >= x && tree[id << 1].min <= y) ans += query(id << 1, l, mid, x, y); if (tree[id << 1 | 1].max >= x && tree[id << 1 | 1].min <= y) ans += query(id << 1 | 1, mid + 1, r, x, y); return ans; } void push_alldown(int id,int l,int r) { if(l==r) { a[l] = tree[id].max; return; } push_down(id); int mid = (l + r) >> 1; push_alldown(id << 1, l, mid); push_alldown(id << 1 | 1, mid + 1, r); } int main() { int n, m; while(scanf("%d%d",&n,&m)!=EOF) { for (int i = 1; i <= n; i++) scanf("%lld", &a[i]); sort(a + 1, a + 1 + n); build(1, 1, n); int cnt = 0; for(int i=1;i<=m;i++) { cin >> s[i]; if (s[i] == "C") scanf("%lld%lld%lld", &lc[i], &rc[i], &num[i]), cnt++; else scanf("%lld%lld", &lc[i], &rc[i]), num[i] = 0; } int tot = 0; for(int i=1;i<=m;i++) { if(s[i]=="C") { ++tot; //push_alldown(1, 1, n); //printf("lc[%d]=%lld rc[%d]=%lld num[%d]=%lld\n", i, lc[i], i, rc[i], i, num[i]); update(1, 1, n, lc[i], rc[i], num[i]); if(tot%2100==0) { push_alldown(1, 1, n); sort(a + 1, a + 1 + n); build(1, 1, n); } } else { int ans = query(1, 1, n, lc[i], rc[i]); printf("%d\n", ans); } } } }