E.体育の授業
テストごとの制限時間
1秒
テストごとのメモリ制限
256メガバイト
入力
標準入力
出力
標準出力
今年、アレックスは学校を卒業し、現在はバーランド州立大学の1年生です。彼にとって、プログラミングを勉強しているにもかかわらず、体育の授業に出席しなければならないことは、まったくの驚きでした。学期の終わりはもうすぐですが、残念ながら、アレックスはまだ1つのレッスンに参加していません。
アレックスは退学を望まないので、学期が終わるまでの残りの就業日数を知りたいので、この日の体育の授業に参加することができます。しかし、BSUでは、稼働日数の計算は複雑な問題です。
ある のn 日(1からに番号が付け期間の終了までの残り のn)、および最初にすべてのそれらの営業日です。その後、大学の職員が次々とq 件の注文を順番に発行し ます。各次数は、3つの数値l、 r 、および kによって特徴付けられます 。
- k = 1の場合 、l からr (両端を含む)までの すべての日 が非稼働日になります。これらの日の一部が以前の注文によって稼働日になった場合でも、これらの日は非稼働日になります。
- k = 2の場合 、l からr (両端を含む)までの すべての日 が稼働日になります。これらの日の一部が以前の注文によって非稼働日になった場合でも、これらの日は稼働日になります。
アレックスが各注文後の残りの営業日数を判断するのを手伝ってください!
入力
最初の行は、一つの整数含ま nは整数1 - 、2行目 のq (1≤ N ≤109、1≤ qは 、期間の終了までの残り日数、および注文の数- ≤3・105)それぞれ。
次に、 Qの 線は、追従 iは三つの整数を含む番目のライン L iは、 rは Iを そして kは Iを 表し 、I番目の順番(1≤ L I ≤は、 rは Iを ≤ nは1≤、 kは I ≤2)。
出力
印刷 q個の 整数を。 それらのi番目は、最初のi 注文が発行されてから期間が終了するまでの残りの稼働日数と等しくなければなりません 。
例
入力
コピー
4 6 1 2 1 3 4 1 2 3 2 1 3 2 2 4 1 1 4 2
出力
コピー
2 0 2 3 1 4
本旨:
Nの長さが1e9までの間隔、3e5操作クエリ。毎回0または1までの間隔をカバーし、変更された総数1を出力します。
解決:
この質問のNは1e9であり、これは明らかに定期的な間隔で書き込むことはできません。したがって、動的な開始点である3e5操作があります。毎回チェーンを追加すると、ログ(N)スペースをさらに開くことに相当し、3e5回は3e5 * log(N)になります。動的開始点と従来の書き込み方法の違いは、ラインセグメントツリーを構築する機能が動的アプリケーションになり、左の子と右の子を配列に置き換える必要があることです。
受け入れられたコード
#pragma GCC optimize(3)
#include<bits/stdc++.h>
#include<unordered_map>
using namespace std;
#define sc scanf
#define Min(x, y) x = min(x, y)
#define Max(x, y) x = max(x, y)
#define ALL(x) (x).begin(),(x).end()
#define SZ(x) ((int)(x).size())
#define pir pair <int, int>
#define MK(x, y) make_pair(x, y)
#define MEM(x, b) memset(x, b, sizeof(x))
#define MPY(x, b) memcpy(x, b, sizeof(x))
#define lowbit(x) ((x) & -(x))
#define P2(x) ((x) * (x))
typedef long long ll;
const int Mod = 1e9 + 7;
const int N = 3e5 + 100;
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
inline ll dpow(ll a, ll b){ ll r = 1, t = a; while (b){ if (b & 1)r = (r*t) % Mod; b >>= 1; t = (t*t) % Mod; }return r; }
inline ll fpow(ll a, ll b){ ll r = 1, t = a; while (b){ if (b & 1)r = (r*t); b >>= 1; t = (t*t); }return r; }
int bt[N * 50];
int ls[N * 50], rs[N * 50], lzy[N * 50];
unordered_map <int, int> rt;
int cnt;
void Pushdown(int o, int len) {
int Llen = len - (len >> 1);
int Rlen = len >> 1;
if (!ls[o]) // 申请左孩子
ls[o] = ++cnt;
if (!rs[o]) // 申请右孩子
rs[o] = ++cnt;
lzy[ls[o]] = lzy[rs[o]] = lzy[o];
bt[ls[o]] = Llen * lzy[o];
bt[rs[o]] = Rlen * lzy[o];
lzy[o] = -1;
}
void Update(int &o, int L, int R, int l, int r, int k) {
int len = R - L + 1;
if (!o)
o = ++cnt, lzy[o] = -1; // 动态开区间
if (L >= l && R <= r) {
bt[o] = len * k;
lzy[o] = k;
return;
}
if (lzy[o] != -1)
Pushdown(o, len);
int mid = (L + R) >> 1;
if (mid >= l)
Update(ls[o], L, mid, l, r, k);
if (mid < r)
Update(rs[o], mid + 1, R, l, r, k);
bt[o] = bt[ls[o]] + bt[rs[o]];
}
int Ask(int o, int L, int R, int l, int r) {
int len = R - L + 1;
if (L >= l && R <= r)
return bt[o];
if (lzy[o] != -1)
Pushdown(o, len);
int mid = (L + R) >> 1, tot = 0;
if (mid >= l)
tot = Ask(ls[o], L, mid, l, r);
if (mid < r)
tot += Ask(rs[o], mid + 1, R, l, r);
return tot;
}
int main()
{
int n, q;
cin >> n >> q;
while (q--) {
int l, r, op;
sc("%d %d %d", &l, &r, &op);
if (op == 2)
op = 0; // 区间置0
Update(rt[1], 1, n, l, r, op);
printf("%d\n", n - Ask(1, 1, n, 1, n));
}
return 0; // 改数组大小!!!用pair记得改宏定义!!!
}