题意:
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