链接:点击打开链接
题意:Alex高中毕业了,他现在是大学新生。虽然他学习编程,但他还是要上体育课,这对他来说完全是一个意外。快要期末了,但是不幸的Alex的体育学分还是零蛋!
Alex可不希望被开除,他想知道到期末还有多少天的工作日,这样他就能在这些日子里修体育学分。但是在这里计算工作日可不是件容易的事情:
从现在到学期结束还有 n 天(从 1 到 n 编号),他们一开始都是工作日。接下来学校的工作人员会依次发出 q 个指令,每个指令可以用三个参数 l,r,k 描述:
如果 k=1,那么从 l 到 r (包含端点)的所有日子都变成非工作日。
如果 k=2,那么从 l 到 r (包含端点)的所有日子都变成工作日。
帮助Alex统计每个指令下发后,剩余的工作日天数
(1≤n≤10^9,1≤q≤3*10^5)
代码:
#include <map>
#include <stack>
#include <queue>
#include <stack>
#include <string>
#include <vector>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <algorithm>
using namespace std;
const int siz=15000005;
int n,m,id;
int ll[siz],rr[siz],sum[siz],lazy[siz];
void pushdown(int l,int r,int rt){
if(lazy[rt]!=-1){
int m=(l+r)>>1;
if(l!=r){ //不是叶子节点则需要开辟左节点或右节点
if(ll[rt]==0) ll[rt]=++id; //从而把标记传下去
if(rr[rt]==0) rr[rt]=++id;
lazy[ll[rt]]=lazy[rt];
lazy[rr[rt]]=lazy[rt];
sum[ll[rt]]=(m-l+1)*lazy[rt];
sum[rr[rt]]=(r-m)*lazy[rt];
}
lazy[rt]=-1;
}
}
void change(int L,int R,int p,int l,int r,int &rt){
if(!rt) rt=++id; //动态开点就是什么时候用什么时候开点
if(L<=l&&r<=R){
lazy[rt]=p;
sum[rt]=p*(r-l+1);
return;
}
pushdown(l,r,rt);
int m=(l+r)>>1;
if(L<=m)
change(L,R,p,l,m,ll[rt]);
if(R>m)
change(L,R,p,m+1,r,rr[rt]);
sum[rt]=sum[ll[rt]]+sum[rr[rt]];
}
int main(){ //因为n特别大,所以可以直接动态开点
int i,j,x,y,z,rt; //复杂度O(qlogn),复杂度可能没有直接
while(scanf("%d%d",&n,&m)!=EOF){ //离散化O(qlogq)优秀,但是实现起来比较简单
id=rt=0;
memset(ll,0,sizeof(ll));
memset(rr,0,sizeof(rr));
memset(sum,0,sizeof(sum));
memset(lazy,-1,sizeof(lazy));
for(i=1;i<=m;i++){
scanf("%d%d%d",&x,&y,&z);
if(z==1)
change(x,y,1,1,n,rt);
else
change(x,y,0,1,n,rt);
printf("%d\n",n-sum[1]);
}
}
return 0;
}
/*
10
3
2 3 1
1 5 1
4 6 1
*/