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<=3105) — 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-tot);
    }
    
    return 0;
}
原文地址:https://www.cnblogs.com/JYYHH/p/8406106.html