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 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 iiorders 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

下午去湘江边的橘子洲van了一圈,然而明天就要去雅礼报道了hhhh

很明显n<=10^9肯定不能用普通的线段树做,虽然可能离散化完了之后会有奇淫技巧能做。。。。但是我首先想到的是动态开点直接打标机下传、、、毕竟线段树一次操作涉及的节点数是log n级别的,就算是区间操作+需要标记下传的话,需要的空间也只是常数大了大,复杂度依然是log n的,而且很多操作还会有重复的区间呢。

于是我就动态开点+线段树打tag瞎做了做,,,本地垃圾笔记本3s才能过极端数据,,,,不过codeforces的评测机跑的飞快,硬生生的缩成了300+ms。
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#define ll long long
#define maxn 200005
using namespace std;
struct node{
    int lc,rc;
    int tag,sum;
}nil[maxn*71];
int n,le,ri,tot;
int q,opt,cnt=1;

inline void work(int v,int tmp,int len){
    if(tmp==-1) nil[v].tag=-1,nil[v].sum=0;
    else nil[v].tag=1,nil[v].sum=len;
}

inline void pushdown(int o,int l,int r){
    int ls=nil[o].lc,rs=nil[o].rc,mid=l+r>>1;
    if(nil[o].tag==-1){
        nil[o].tag=0;
        work(ls,-1,mid-l+1);
        work(rs,-1,r-mid);
    }
    else if(nil[o].tag==1){
        nil[o].tag=0;
        work(ls,1,mid-l+1);
        work(rs,1,r-mid);
    }
}

void update(int u,int l,int r){
    if(l>=le&&r<=ri){
        int pre=nil[u].sum;
        work(u,opt,r-l+1);
        tot+=nil[u].sum-pre;
        return;
    }
    if(!nil[u].lc) nil[u].lc=++cnt;
    if(!nil[u].rc) nil[u].rc=++cnt;
    pushdown(u,l,r);

    int mid=l+r>>1;
    if(le<=mid) update(nil[u].lc,l,mid);
    if(ri>mid) update(nil[u].rc,mid+1,r);

    nil[u].sum=nil[nil[u].lc].sum+nil[nil[u].rc].sum;
}

int main(){
//    freopen("data.in","r",stdin);
//    freopen("data.out","w",stdout);

    int root=1;
    nil[1]=(node){0,0,0,0};
    scanf("%d%d",&n,&q);
    while(q--){
        scanf("%d%d%d",&le,&ri,&opt);
        opt=(opt==2?-1:1);
        update(root,1,n);
        printf("%d\n",n-tot);
    }

    return 0;
}

原文地址:https://www.cnblogs.com/JYYHH/p/8406106.html

时间: 2024-08-03 19:53:10

Codeforces 915 E Physical Education Lessons的相关文章

【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 (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

[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}$的范围显然不可能是朴素线段树

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

CF915E Physical Education Lessons

题意: Alex高中毕业了,他现在是大学新生.虽然他学习编程,但他还是要上体育课,这对他来说完全是一个意外.快要期末了,但是不幸的Alex的体育学分还是零蛋! Alex可不希望被开除,他想知道到期末还有多少天的工作日,这样他就能在这些日子里修体育学分.但是在这里计算工作日可不是件容易的事情: 从现在到学期结束还有 n 天(从 1 到 n 编号),他们一开始都是工作日.接下来学校的工作人员会依次发出 q 个指令,每个指令可以用三个参数 l,r,k 描述: 如果 k=1,那么从 l 到 r (包含端

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

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

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

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]表示数位