4298. 【NOIP2015模拟11.2晚】我的天

Description

很久很以前,有一个古老的村庄——xiba村,村子里生活着n+1个村民,但由于历届村长恐怖而且黑暗的魔法统治下,村民们各自过着独立的生活,完全没有意识到其他n个人的存在。
但有一天,村民xiba臻无意中也得到了魔法,并发现了这个恐怖的事实。为了反抗村长,他走遍了全世界,找到了其他n个村民,并组织他们发动革命。但让这n个素不相识的村民(xiba臻已跟他们认识)同心协力去抵抗村长是很困难的,所以xiba臻决定先让他们互相认识。
这里,xiba臻用了xiba村特有的xiba思维:先让这n个人排成一列,并依次从1-n标号。然后每次xiba臻会选出一个区间[l, r],在这个区间中的人会去认识其他在这个区间中的人,但已经认识过得不会再去认识。这样,进行m次操作后,xiba臻认为这n个人能认识到许多人。
但是,为了精确地知道当前有多少对人已经认识了,xiba臻想要知道每次操作后会新产生出多少对认识的人,但这已是xiba思维无法解决的事了,你能帮帮他吗?

Input

第一行两个整数n,m。
接下来m行每行两个整数li,ri,表示每次操作的区间。

Output

共m行,每行一个整数ans_i,表示第i次操作后新产生出ans_i对认识的人。

Sample Input

5 5
2 3
2 4
3 5
1 5
2 4

Sample Output

1
2
2
5
0

Data Constraint

对于20%的数据,1≤n,m≤100。
对于50%的数据,1≤n,m≤5000。
对于100%的数据,1≤n,m≤300000,1≤li≤ri≤n。

Solution

可以看成每一个人对后面的连续的一段人是否有关系。

那么设f[ i ]表示i这个人和i+1到f[ i ]的人有关系。

则每次将L~R的区间的f[ i ]与R取max,最后所有f的变化值即为ans。

那么可以用吉司机线段树维护。

Code

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<ctime>
#define I int
#define ll long long
#define ls x<<1
#define rs ls|1
#define F(i,a,b) for(I i=a;i<=b;i++)
#define Fd(i,a,b) for(I i=a;i>=b;i--)
#define N 1000003
using namespace std;
I n,m,f[N],x,y,inf=0x7fffffff;
ll ans;
struct node{I mn,mn2,cmn,tmx;ll s;}t[N<<2];
void update(I x){
	t[x].s=t[ls].s+t[rs].s;
	if(t[ls].mn==t[rs].mn){
		t[x].mn=t[ls].mn,t[x].cmn=t[ls].cmn+t[rs].cmn;
		t[x].mn2=min(t[ls].mn2,t[rs].mn2);
	}
	else if(t[ls].mn<t[rs].mn){
		t[x].mn=t[ls].mn,t[x].cmn=t[ls].cmn;
		t[x].mn2=min(t[ls].mn2,t[rs].mn);
	}
	else{
		t[x].mn=t[rs].mn,t[x].cmn=t[rs].cmn;
		t[x].mn2=min(t[ls].mn,t[rs].mn2);
	}
}
void push_max(I x,I v){
	if(t[x].mn>=v) return;
	t[x].s+=1LL*(v-t[x].mn)*t[x].cmn;
	t[x].mn=t[x].tmx=v;
}
void down(I x){
	if(t[x].tmx!=-inf){push_max(ls,t[x].tmx),push_max(rs,t[x].tmx);}
	t[x].tmx=-inf;
}
void build(I x=1,I l=1,I r=n){
	t[x].tmx=-inf;
	if(l==r){
		t[x].mn=t[x].s=l,t[x].cmn=1,t[x].mn2=inf;
		return;
	}
	I M=l+r>>1;
	build(ls,l,M),build(rs,M+1,r);
	update(x);
}
void work(I l2,I r2,I v,I x=1,I l=1,I r=n){
	if(r<l2||l>r2||t[x].mn>=v) return;
	if(l>=l2&&r<=r2&&t[x].mn2>v){
		if(t[x].mn<v) ans+=1LL*(v-t[x].mn)*t[x].cmn;
		return push_max(x,v);
	}
	I M=l+r>>1;
	down(x);
	work(l2,r2,v,ls,l,M),work(l2,r2,v,rs,M+1,r);
	update(x);
}
I main(){
	freopen("ohmygod.in","r",stdin);
	freopen("ohmygod.out","w",stdout);
	scanf("%d%d",&n,&m);
	build();
	while(m--){
		scanf("%d%d",&x,&y);
		ans=0;
		work(x,y,y);
		printf("%lld\n",ans);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/zsjzliziyang/article/details/107801185