長すぎるセグメントツリー手が生まれてきた再生しないでください
問題A:高速道路
偽所望のタイトル、明らかに分母\(R&LT C_ { - }。1 + L ^ 2 \) 。全てのサブセグメント区間内と求めてすべてがあります。
そして、ツリーライン区間の合併を検討し、それを行うように見えることはできません。
そして、SXレッドサン郭は私を啓発する、我々は染色に似ツリーのアイデアを取ることができ、各エッジは、いくつかの後にすることができ考えます。
以下のために、比較した場合、これは明らかである\((R - I + 1 - )(I L + 1)\) その分子である。\(\ SUM \ _制限} {I = L ^ R&LT(R&LT - + I. 1) (I - 1 + L)W_i \) 。
簡略化は、約\(\ SUM \ _制限} {I = L ^ R&LT(R&LT - 1 + L - LR)W_i +(L + R&LT)W_i I - I 2 W_i ^ \) 。
3セグメントツリータグに注意してください。\(= W_i S_1、S_2 I = W_i、W_i S_3 = I ^ 2 \) 。
間隔は一緒に直接組み込みます。
そして、右側の変更を検討し、それを追加することです\(V(R&LTを- 。1 + L - LR)\) \(I SUM \ V(L + R&LT)\)と$ -VI ^ 2 $。
再记\(S_4 =合計I、S_5 = \合計\ I ^ 2 \) 。
この質問は終了されるだろう。
ピットに注意してください。
- その時点までに、私たちはそのラインを維持し、我々はそれに対処する必要があります
- 長い長い長い長い開くために開くことができます!!躊躇しないでください!!あなたWA20あれば、それは長い長い開かなかった開くしようとしています
#include <bits/stdc++.h>
#define ll long long
const int N = 100000 + 233;
ll n, m, sum[5]; char opt[5];
struct SegTree { ll l, r, s[8], tag; } t[N << 2];
inline void Pushup(ll p) {
for (int i = 1; i <= 3; i++)
t[p].s[i] = t[p << 1].s[i] + t[p << 1 | 1].s[i];
}
ll gcd(ll x, ll y) {
return y == 0 ? x : gcd(y, x % y);
}
void Build(ll p, ll l, ll r) {
t[p].l = l, t[p].r = r;
if (l == r) return (void) (t[p].s[4] = l, t[p].s[5] = l * l);
ll mid = (l + r) >> 1;
Build(p << 1, l, mid), Build(p << 1 | 1, mid + 1, r);
for (int i = 4; i <= 5; i++)
t[p].s[i] = t[p << 1].s[i] + t[p << 1 | 1].s[i];
}
inline void Add(ll p, ll k) {
t[p].s[1] += (t[p].r - t[p].l + 1) * k;
t[p].s[2] += k * t[p].s[4];
t[p].s[3] += k * t[p].s[5];
t[p].tag += k;
}
inline void Pushdown(ll p) {
Add(p << 1, t[p].tag), Add(p << 1 | 1, t[p].tag);
t[p].tag = 0;
}
void Change(ll p, ll l, ll r, ll v) {
if (l <= t[p].l && r >= t[p].r) return (void) Add(p, v);
ll mid = (t[p].l + t[p].r) >> 1;
if (t[p].tag) Pushdown(p);
if (l <= mid) Change(p << 1, l, r, v);
if (r > mid) Change(p << 1 | 1, l, r, v);
Pushup(p);
}
void Ask(ll p, ll l, ll r) {
if (l <= t[p].l && r >= t[p].r) {
for (int i = 1; i <= 3; i++)
sum[i] += t[p].s[i];
return;
}
ll mid = (t[p].l + t[p].r) >> 1;
if (t[p].tag) Pushdown(p);
if (l <= mid) Ask(p << 1, l, r);
if (r > mid) Ask(p << 1 | 1, l, r);
}
inline void print(ll x, ll y) {
ll g = gcd(x, y);
printf("%lld/%lld\n", x / g, y / g);
}
signed main() {
scanf("%lld%lld", &n, &m);
Build(1, 1, n);
for (ll i = 1, l, r; i <= m; i++) {
ll v;
scanf("%s%lld%lld", opt, &l, &r); r--;
if (opt[0] == 'C') {
scanf("%lld", &v), Change(1, l, r, v);
} else {
sum[1] = sum[2] = sum[3] = 0;
Ask(1, l, r);
ll a = (r - l + 1 - l * r) * sum[1] + (r + l) * sum[2] - sum[3];
ll b = (r - l + 2) * (r - l + 1) / 2;
print(a, b);
}
}
return 0;
}
問題D:ソート
第四に(この問題に耳を傾け
死の家の興Zeyuの最初の審理はSJZEZを話します
SDFZでの2勝目は、高低温の鳩鳩の話を聞きます
TYWZで三回目は本当に赤い日リカルド-SXを聴いて話すために一緒に取得
第四に巨大な巨大なコアラはHZに話を聞きます
本当の公共の問題(
この質問の最も重要な点は、一箇所だけを依頼することです、と答えは明確に単調である、あなたは半分に逃げます
配列をソートすることは、セグメントツリーと「ソート」プロセスを維持できるように、0より大きく、1以下表し、01の配列に変わり、あまりにチを研削します。
しかし、行くことができるどのような水、バケツ行の最適化神を超えるデータの問題(((
#include <bits/stdc++.h>
const int N = 100005 + 233;
int n, m, q, ans, a[N];
struct Command { int l, r, op; } cmd[N];
struct SegTree {
int l, r, sum, tag;
#define l(p) tree[p].l
#define r(p) tree[p].r
#define sum(p) tree[p].sum
#define tag(p) tree[p].tag
#define ls(p) p << 1
#define rs(p) p << 1 | 1
} tree[N << 2];
inline int R() {
int a = 0; char c = getchar();
while (!isdigit(c)) c = getchar();
while (isdigit(c)) a = a * 10 + c - '0', c = getchar();
return a;
}
void Build(int p, int l, int r, int v) {
l(p) = l, r(p) = r, tag(p) = -1;
if (l == r) return (void) (sum(p) = a[l] >= v);
int mid = (l + r) >> 1;
Build(ls(p), l, mid, v), Build(rs(p), mid + 1, r, v);
sum(p) = sum(ls(p)) + sum(rs(p));
}
void Pushdown(int p) {
if (tag(p) != -1) {
sum(ls(p)) = (r(ls(p)) - l(ls(p)) + 1) * tag(p);
sum(rs(p)) = (r(rs(p)) - l(rs(p)) + 1) * tag(p);
tag(ls(p)) = tag(rs(p)) = tag(p);
tag(p) = -1;
}
}
void Change(int p, int l, int r, int v) {
if (l <= l(p) && r >= r(p)) {
sum(p) = (r(p) - l(p) + 1) * v;
tag(p) = v;
} else {
Pushdown(p);
int mid = (l(p) + r(p)) >> 1;
if (l <= mid) Change(ls(p), l, r, v);
if (r > mid) Change(rs(p), l, r, v);
sum(p) = sum(ls(p)) + sum(rs(p));
}
}
int Query(int p, int l, int r) {
if (l <= l(p) && r >= r(p))
return sum(p);
Pushdown(p);
int mid = (l(p) + r(p)) >> 1, ret = 0;
if (l <= mid) ret += Query(ls(p), l, r);
if (r > mid) ret += Query(rs(p), l, r);
return ret;
}
bool Check(int x) {
Build(1, 1, n, x);
for (int i = 1; i <= m; i++) {
int cnt = Query(1, cmd[i].l, cmd[i].r);
if (cnt != 0 && cnt != cmd[i].r - cmd[i].l + 1) {
if (cmd[i].op) {
Change(1, cmd[i].l, cmd[i].l + cnt - 1, 1);
Change(1, cmd[i].l + cnt, cmd[i].r, 0);
} else {
Change(1, cmd[i].l, cmd[i].r - cnt, 0);
Change(1, cmd[i].r - cnt + 1, cmd[i].r, 1);
}
}
}
return Query(1, q, q);
}
signed main() {
n = R(), m = R();
for (int i = 1; i <= n; i++)
a[i] = R();
for (int i = 1; i <= m; i++)
cmd[i].op = R(), cmd[i].l = R(), cmd[i].r = R();
q = R();
int l = 1, r = n, mid;
while (l <= r) {
mid = (l + r) >> 1;
if (Check(mid)) {
ans = mid;
l = mid + 1;
} else r = mid - 1;
}
return !printf("%d\n", ans);
}