CodeForces-915E. Physical Education Lessons(离散化+线段树)及离散化详解

E. Physical Education Lessons

题目链接https://codeforces.com/contest/915/problem/E

time limit per test               memory limit per test

1 second                            256 megabytes

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 n days left before the end of the term (numbered from 1 to n), and initially all of them are working days. Then the university staff sequentially publishes q orders, one after another. Each order is characterised by three numbers lr and k:

  • If k = 1, then all days from l to r (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 = 2, then all days from l to r (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!

Input

The first line contains one integer n, and the second line — one integer q (1 ≤ n ≤ 10^9, 1 ≤ q ≤ 3·10^5) — the number of days left before the end of the term, and the number of orders, respectively.

Then q lines follow, i-th line containing three integers liri and ki representing i-th order (1 ≤ li ≤ ri ≤ n, 1 ≤ ki ≤ 2).

Output

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

Example

Input

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

Output

2
0
2
3
1
4

题目大意:给定1-n的一段已经填充的区间,每次给出 x  y  z  的询问,z == 1 时将 x - y 区间全部空出来,否则全部填充,问最后一共有多少填充的区间。

很显然,n的范围是1e9。。。只有3e5个区间,那么很容易想到离散化。这里离散化需要注意的是

1.隔板,将原来分开的两个数中间插入一个数。比如对于数据

7
10
5 7 1
5 6 2
7 7 2
6 7 2
5 5 1
3 6 2
1 3 2
5 6 1
1 3 1
6 7 1

就是第三测试点,把所有的数据跳出来的话就是1 3 5 6 7。那么我们如果将其离散化后就是1 2 3 4 5。但如果我们将5到6的区间删空了的话,也就是说3-4没了,我们得到的答案是区间1-2的值,也就是最终答案3。。。QAQ所以要加入隔板,对于3 5 这种数据加一个4的隔板就好了,但对于像54   1212121 这种数,我们就需要加上55 和 1212120 两个隔板:

sort(b+1,b+1+cnt);
int p=b[1],tot=1;
len[1]=b[1];
for (int i=2; i<=cnt; i++) {
	if (b[i]!=p) {
		if(b[i]-b[i-1]==2) {//加一个隔板
			len[++tot]=p+1;
		} 
		else if (b[i]-b[i-1]>2) {//加两个隔板
			len[++tot]=b[i-1]+1;
			len[++tot]=b[i]-1;
		}
		p=b[i];
		q[p]=++tot;
		len[tot]=b[i];
	}
}

2.注意头和尾,它的区间中可能并没有1,所以我们需要对头减一作为最小值,尾巴的话就是N了:

int mi=inf;
for (int i=1; i<=m; i++) {
	int l,r,id;
	in(l);in(r);in(id);
	a[i].l=l;a[i].r=r;a[i].id=id;
	b[++cnt]=l;b[++cnt]=r;
	mi=min(min(l,r),mi);
}
if (mi>1) b[++cnt]=mi-1;
b[++cnt]=n;

那么接下来就是线段树的操作了,我们的先初始化线段树叶子结点全部为它的区间大小(表示已经填充好了)然后往上加:

void build(int l,int r,int rt)
{
    f[rt]=-1;
    if (l==r) {
    	tree[rt]=len[r]-len[l-1];
    	return;
	}
    int mid=(l+r)>>1;
    build(lson);build(rson);
    tree[rt]=tree[ls]+tree[rs];
}

接下来就是和区间染色一样的无脑更新了,答案我们直接输出tree[1]就好了。注意离散化别用unordered_map或者map,会T。。。

以下是AC代码:
 

#include <bits/stdc++.h>
using namespace std;

#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define ls rt<<1
#define rs rt<<1|1

const int mac=3e6+10;
const int inf=1e9+10;

int tree[mac<<2],f[mac<<2];
int len[mac];//保留每个离散化数据原始的离1的距离
unordered_map<int,int>q;

void build(int l,int r,int rt)
{
    f[rt]=-1;
    if (l==r) {
    	tree[rt]=len[r]-len[l-1];
    	return;
	}
    int mid=(l+r)>>1;
    build(lson);build(rson);
    tree[rt]=tree[ls]+tree[rs];
}

void down(int l,int r,int rt)
{
    int mid=(l+r)>>1;
    tree[ls]=f[rt]*(len[mid]-len[l-1]);tree[rs]=f[rt]*(len[r]-len[mid]);
    f[ls]=f[rs]=f[rt];
    f[rt]=-1;
}

void update(int l,int r,int rt,int L,int R,int val)
{
    if (l>=L && r<=R){
        f[rt]=val;
        tree[rt]=val*(len[r]-len[l-1]);
        return;
    }
    if (f[rt]!=-1) down(l,r,rt);
    int mid=(l+r)>>1;
    if (mid>=L) update(lson,L,R,val);
    if (mid<R) update(rson,L,R,val);
    tree[rt]=tree[ls]+tree[rs];
}

void in(int &x)
{
    int f=0;
    char ch=getchar();
    while (ch<'0' || ch>'9') ch=getchar();
    while (ch>='0' && ch<='9') f=(f<<3)+(f<<1)+ch-'0',ch=getchar();
    x=f;
}

struct node
{
    int l,r,id;
}a[mac];
int b[mac];

int main()
{
    int n,m;
    in(n);in(m);
    int cnt=0;
    int mi=inf;
    for (int i=1; i<=m; i++){
        int l,r,id;
        in(l);in(r);in(id);
        a[i].l=l;a[i].r=r;a[i].id=id;
        b[++cnt]=l;b[++cnt]=r;
        mi=min(min(l,r),mi);
    }
    if (mi>1) b[++cnt]=mi-1;
    b[++cnt]=n;
    sort(b+1,b+1+cnt);
    int p=b[1],tot=1;
    len[1]=b[1];
    for (int i=2; i<=cnt; i++){
        if (b[i]!=p){
        	if(b[i]-b[i-1]==2) {
        		//q[p+1]=++tot;
        		len[++tot]=p+1;
			}
			else if (b[i]-b[i-1]>2) {
				//q[b[i-1]+1]=++tot;
				len[++tot]=b[i-1]+1;
				//q[b[i]-1]=++tot;
				len[++tot]=b[i]-1;
			}
			p=b[i];q[p]=++tot;
            len[tot]=b[i];
        }
    }
    build(1,tot,1);
    for (int i=1; i<=m; i++){
    	int l=lower_bound(len+1,len+1+tot,a[i].l)-len;
    	int r=lower_bound(len+1,len+1+tot,a[i].r)-len;
        if (a[i].id==1) update(1,tot,1,l,r,0);
        else update(1,tot,1,l,r,1);
        printf ("%d\n",tree[1]);
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值