CF915E Physical Education Lessons

题意:

Alex高中毕业了,他现在是大学新生。虽然他学习编程,但他还是要上体育课,这对他来说完全是一个意外。快要期末了,但是不幸的Alex的体育学分还是零蛋!

Alex可不希望被开除,他想知道到期末还有多少天的工作日,这样他就能在这些日子里修体育学分。但是在这里计算工作日可不是件容易的事情:

从现在到学期结束还有 n 天(从 1 到 n 编号),他们一开始都是工作日。接下来学校的工作人员会依次发出 q 个指令,每个指令可以用三个参数 l,r,k 描述:

  • 如果 k=1,那么从 l 到 r (包含端点)的所有日子都变成非工作日。
  • 如果 k=2,那么从 l 到 rr(包含端点)的所有日子都变成工作日。

帮助Alex统计每个指令下发后,剩余的工作日天数。

输入格式:

第一行一个整数 n,第二行一个整数 q (1≤n≤109,1≤q≤3⋅105),分别是剩余的天数和指令的个数。

接下来 q 行,第 i 行有 3 个整数 li?,ri?,ki?,描述第 i 个指令 (1≤li?,ri?≤n,1≤k≤2)。

输出格式:

输出 q 行,第 i 行表示第 i 个指令被下发后剩余的工作日天数。

Translated by 小粉兔

题目描述

This year Alex has finished school, and now he is a first-year student of Berland State University. For him it was a total surprise that even though he studies programming, he still has to attend physical education lessons. The end of the term is very soon, but, unfortunately, Alex still hasn‘t attended a single lesson!

Since Alex doesn‘t want to get expelled, he wants to know the number of working days left until the end of the term, so he can attend physical education lessons during these days. But in BSU calculating the number of working days is a complicated matter:

There are nn days left before the end of the term (numbered from 11 to nn ), and initially all of them are working days. Then the university staff sequentially publishes qq orders, one after another. Each order is characterised by three numbers ll , rr and kk :

  • If k=1k=1 , then all days from ll to rr (inclusive) become non-working days. If some of these days are made working days by some previous order, then these days still become non-working days;
  • If k=2k=2 , then all days from ll to rr (inclusive) become working days. If some of these days are made non-working days by some previous order, then these days still become working days.

Help Alex to determine the number of working days left after each order!

输入输出格式

输入格式:

The first line contains one integer nn , and the second line — one integer qq ( 1<=n<=10^{9}1<=n<=109, 1<=q<=3·10^{5}1<=q<=3⋅105 ) — the number of days left before the end of the term, and the number of orders, respectively.

Then qq lines follow, ii -th line containing three integers l_{i}li? , r_{i}ri? and k_{i}ki? representing ii -th order ( 1<=l_{i}<=r_{i}<=n1<=li?<=ri?<=n , 1<=k_{i}<=21<=ki?<=2 ).


输出格式:

Print qq integers. ii -th of them must be equal to the number of working days left until the end of the term after the first ii orders are published.

输入输出样例

输入样例#1:

4
6
1 2 1
3 4 1
2 3 2
1 3 2
2 4 1
1 4 2

输出样例#1:

2
0
2
3
1
4

Solution:

  本题动态开点线段树。

  题目和那个开关灯的用线段树解决的问题是一样的,只不过区间范围比那个大。

  对于本题当然可以离散化,但更为简单的就是动态开点了。

  我们对于每次修改的一段区间,都在$[1,n]$范围内二分,对于没有建节点的区间就兴建节点维护,然后加上懒惰标记,记得下放标记时也得判断子节点有无并动态开节点就好了。(注意,空间一定得开大,粗略的算下得开到$2\log n$倍$q$)

代码:

/*Code by 520 -- 9.25*/
#include<bits/stdc++.h>
#define il inline
#define ll long long
#define RE register
#define For(i,a,b) for(RE int (i)=(a);(i)<=(b);(i)++)
#define Bor(i,a,b) for(RE int (i)=(b);(i)>=(a);(i)--)
using namespace std;
const int N=300005;
int n,m,root,cnt;
int ls[N*50],rs[N*50],sum[N*50],lazy[N*50];

int gi(){
    int a=0;char x=getchar();
    while(x<‘0‘||x>‘9‘) x=getchar();
    while(x>=‘0‘&&x<=‘9‘) a=(a<<3)+(a<<1)+(x^48),x=getchar();
    return a;
}

il void pushup(int rt){sum[rt]=sum[ls[rt]]+sum[rs[rt]];}

il void pushdown(int l,int r,int rt){
    if(~lazy[rt]){
        if(l!=r) {
            if(!ls[rt]) ls[rt]=++cnt;
            if(!rs[rt]) rs[rt]=++cnt;
            lazy[ls[rt]]=lazy[rt],
            lazy[rs[rt]]=lazy[rt];
            sum[ls[rt]]=((l+r>>1)-l+1)*lazy[rt];
            sum[rs[rt]]=(r-(l+r>>1))*lazy[rt];
        }
        lazy[rt]=-1;
    }
}

void update(int L,int R,int x,int l,int r,int &rt){
    if(!rt) rt=++cnt;
    if(L<=l&&R>=r){lazy[rt]=x;sum[rt]=(r-l+1)*x;return;}
    pushdown(l,r,rt);
    int m=l+r>>1;
    if(L<=m) update(L,R,x,l,m,ls[rt]);
    if(R>m) update(L,R,x,m+1,r,rs[rt]);
    pushup(rt);
}

int main(){
    memset(lazy,-1,sizeof(lazy));
    n=gi(),m=gi();
    int x,y,z;
    while(m--){
        x=gi(),y=gi(),z=gi();
        if(z==1) update(x,y,1,1,n,root);
        else update(x,y,0,1,n,root);
        printf("%d\n",n-sum[1]);
    }
    return 0;
}

原文地址:https://www.cnblogs.com/five20/p/9710559.html

时间: 2024-11-08 21:26:39

CF915E Physical Education Lessons的相关文章

CF915E Physical Education Lessons|动态开点线段树

动态开点线段树 题目暗示了区间修改,所以我们自然想到了用线段树来维护非工作日的天数. 然而我们再看一下数据范围,天数n的范围是\(1 \le n \le 10^9\),像普通线段树一样预处理显然会爆空间. 天无绝人之路,我们看一下修改个数,$1\le q \le 3 \cdot 10^5 $, 比天数少很多,这也意味着,我们预先处理好的线段树有些节点并没有用 能否优化呢?答案是肯定的,这就是动态开点线段树,顾名思义,我们只要到用某个节点的时候,才分配一个点给它,这样使得我们使用的空间大大减少.其

【CodeForces】915 E. Physical Education Lessons 线段树

[题目]E. Physical Education Lessons [题意]10^9范围的区间覆盖,至多3*10^5次区间询问. [算法]线段树 [题解]每次询问至多增加两段区间,提前括号分段后线段树. #include<cstdio> #include<cctype> #include<set> #include<algorithm> using namespace std; int read(){ char c;int s=0,t=1; while(!i

[Educational Codeforces Round 36]E. Physical Education Lessons

[Educational Codeforces Round 36]E. Physical Education Lessons <题意概括> 给定一个长度为$N\left(1\leqslant N\leqslant10^{9}\right)$的区间 $Q\left(1\leqslant Q\leqslant3\cdot10^{5}\right)$次将区间$\left[L,R\right]$Set为0或1,每次Set后输出区间总和 <做法> $10_{9}$的范围显然不可能是朴素线段树

Codeforces 915 E Physical Education Lessons

题目描述 This year Alex has finished school, and now he is a first-year student of Berland State University. For him it was a total surprise that even though he studies programming, he still has to attend physical education lessons. The end of the term i

Physical Education Lessons CodeForces - 915E (动态开点线段树)

Physical Education Lessons CodeForces - 915E This year Alex has finished school, and now he is a first-year student of Berland State University. For him it was a total surprise that even though he studies programming, he still has to attend physical

Educational Codeforces Round 36 (Rated for Div. 2) E. Physical Education Lessons(动态开点线段树)

链接: https://codeforces.com/problemset/problem/915/E 题意: This year Alex has finished school, and now he is a first-year student of Berland State University. For him it was a total surprise that even though he studies programming, he still has to atten

Physical Education Lessons Codeforces - 915E

http://codeforces.com/problemset/problem/915/E 大概有几种思路: 1.动态开点线段树+标记下传 #1.1标记永久化:想了一会没想出来 1.2可以先扫一遍询问把所有需要的点建出来,然后pushdown就不管没建出来的点了,空间跟标记永久化一样 2.离散化+线段树 3.用splay维护区间(估计没人愿意去写) 4.用一个set<pair<int,int>>记所有非工作日(或工作日)区间,修改就暴力找到相关的区间去改 由于每一次操作最多多出O

Codeforces 394D Physical Education and Buns 胡搞

题目链接:点击打开链接 题意:给定n个数的序列(能够排序) 操作一次能够使得某个数++或--. 问最少操作几次使得序列变成一个等差序列 输出: 第一行输出最少操作的次数 第二行输出等差数列里的最小项 和 公差的绝对值. 思路:枚举公差,公差范围一定是0到 2Max. 先排个序. 我们使得首项不变.形成一个等差数列. 然后让整个数列位移至 操作后的数组的差值 最小值 == 0.这样这个数列的操作次数= 最大的差值/2. done. #include <iostream> #include <

URAL 2052 Physical Education(数位dp)

 题意:给出一个自然数数列,按照每个数的所有数位之和作为第一关键字,每个数的大小作为第二关键字升序排序,位置不变的数的个数是多少. 思路:首先可以证明,对于数位和为i的所有数,最多只可能有一个位置不变,这个可以直观的猜想一下,因为如果有一个数字位置不变,那么对于排序后的序列,这个数后面的所有数的增长速度都大于自然数序列的增长速度,所以不可能再有第二个. 假设我们当前求出了数位和为i的区间为[l, r],令query(a, b)表示1到a这段区间内数位和为b的数的个数,用su[i-1]表示数位