HDU6888 2020CCPC网络选拔赛A art class(Segment tree beats!\吉老师线段树)

HDU 6888 2020CCPC网络选拔赛A art class(Segment tree beats!\吉老师线段树)

题意:

在笛卡尔坐标系下,一开始没有任何东西。
然后每次操作可以总结为 ( l , r , h ) (l,r,h) (l,r,h),表示在坐标(l,0)到坐标(r,h)画一个实心矩形。问每次操作后的图形周长

题解:

由于每个举行都是贴着x轴放置的,所以横向边之和可以用线段是区间覆盖来做。关键是纵向边之和如何计算。
现在我们来讨论纵向边如何计算:
可以知道一次操作相当于对所有 i ∈ [ l , r ] i\in[l,r] i[l,r]执行操作 m a x ( a [ i ] , h ) max(a[i],h) max(a[i],h),然后查询是求 ∑ ∣ a [ i ] − a [ i + 1 ] ∣ \sum|a[i]-a[i+1]| a[i]a[i+1]
对于前一半我们很容易先到这个可以用吉老师线段树来操作,并用来维护 ∑ ∣ a [ i ] − a [ i + 1 ] ∣ \sum|a[i]-a[i+1]| a[i]a[i+1]。那这个要怎么维护呢?
对于节点 [ l , r ] [l,r] [l,r]我们维护的是 i ∈ [ l , r − 1 ] i\in[l,r-1] i[l,r1](假设区间最小值为k)满足 a [ i ] , a [ i + 1 ] a[i],a[i+1] a[i]a[i+1]有且仅有一个为最小值的i的个数。因此,假设区间满足条件的个数为x,且区间当前最小值变大y,则区间答案的变化为 x ∗ y x*y xy
注意,这种让区间最小值集体变大的操作,不能使得区间的最小值变得比区间严格次小值大。

代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+5;
const int mod=1e9+7;
#define pb push_back
#define fi first
#define se second
#define all(x) (x).begin(),(x).end()
#define rep(i,a,n) for (int i=a;i<=n;i++)
#define per(i,a,n) for (int i=n;i>=a;i--)
typedef long long ll;
typedef double db;
typedef vector<int> vi;
typedef pair<int,int> pii;
ll qpow(ll a,ll b){ll ans=1;a%=mod;assert(b>=0);for(;b;b>>=1){if(b&1)ans=ans*a%mod;a=a*a%mod;}return ans;}
ll gcd(ll a,ll b){return b>0?gcd(b,a%b):a;}
int n,m,T,N;
int lz[maxn<<2];
struct node{
	ll mi,si,cnt,l,r,len;
	ll val,val1;
	node(){
		mi=si=cnt=l=r=val=len=val1=0;
	}
	void Max(const ll& C){
		if(C<=mi) return;
		l=max(l,C);
		r=max(r,C);
		val-=1ll*cnt*(C-mi);
		mi=C;
	}
}tr[maxn<<2];
vi v;
#define lson rt<<1
#define rson rt<<1|1
void pushup(const int& rt){
	tr[rt].cnt=0;
	tr[rt].l=tr[lson].l;
	tr[rt].r=tr[rson].r;
	tr[rt].val=tr[lson].val+tr[rson].val;
	tr[rt].mi=min(tr[lson].mi,tr[rson].mi);
	tr[rt].si=min(tr[lson].si,tr[rson].si);
	if(tr[lson].mi^tr[rson].mi) tr[rt].si=min(tr[rt].si,max(tr[lson].mi,tr[rson].mi));
	if(tr[rt].mi==tr[lson].mi) tr[rt].cnt+=tr[lson].cnt;
	if(tr[rt].mi==tr[rson].mi) tr[rt].cnt+=tr[rson].cnt;
	if(tr[lson].r+tr[rson].l!=2ll*tr[rt].mi&&(tr[lson].r==tr[rt].mi||tr[rson].l==tr[rt].mi)){
		tr[rt].cnt++;
	}
	tr[rt].val+=abs(tr[rson].l-tr[lson].r);
}
void pushdown(const int& rt){
	tr[lson].Max(tr[rt].mi);
	tr[rson].Max(tr[rt].mi);
}
void build(int l,int r,int rt){
	lz[rt]=0;
	tr[rt]=node();
	if(l==r){
		tr[rt]=node();
		tr[rt].si=INT_MAX;
		tr[rt].len=v[l]-v[l-1];
		return;
	}
	int mid=l+r>>1;
	build(l,mid,lson);
	build(mid+1,r,rson);
	pushup(rt);
	tr[rt].len=tr[lson].len+tr[rson].len;
}
void update1(int L,int R,int l,int r,int rt){
	if(r<L||R<l) return;
	if(L<=l&&r<=R){
		lz[rt]=1;
		tr[rt].val1=tr[rt].len;
		return;
	}
	if(lz[rt]){
		lz[lson]=lz[rson]=1;
		tr[lson].val1=tr[lson].len;
		tr[rson].val1=tr[rson].len;
		lz[rt]=0;
	}
	int mid=l+r>>1;
	update1(L,R,l,mid,lson);
	update1(L,R,mid+1,r,rson);
	tr[rt].val1=tr[lson].val1+tr[rson].val1;
}
void update(ll C,int L,int R,int l,int r,int rt){
	if(r<L||R<l) return;
	if(C<=tr[rt].mi) return;
	if(L<=l&&r<=R&&tr[rt].si>C){
		tr[rt].Max(C);
		return;
	}
	pushdown(rt);
	int mid=l+r>>1;
	update(C,L,R,l,mid,lson);
	update(C,L,R,mid+1,r,rson);
	pushup(rt);
}
struct Question{
	int l,r,h;
}q[maxn];
int getId(int x){
	return lower_bound(all(v),x)-v.begin()+1;
}
int main() {
	scanf("%d",&T);
	while(T--){
		scanf("%d",&n);	
		v.clear();
		for(int ql,qr,qh,i=1;i<=n;i++){
			scanf("%d%d%d",&ql,&qr,&qh);
			q[i]={ql,qr,qh};  
			v.pb(ql);
			v.pb(qr);
		}
		v.pb(0);
		v.pb(1e9);
		sort(all(v));
		v.erase(unique(all(v)),v.end());
		N=v.size();
		build(1,N,1);
		for(int ql,qr,i=1;i<=n;i++){
			ql=getId(q[i].l);
			qr=getId(q[i].r);
			update1(ql,qr-1,1,N,1);
			update(q[i].h,ql,qr-1,1,N,1);
			printf("%lld\n",tr[1].val+2ll*tr[1].val1);
		}
	}
	return 0;
}
/*
2
3
2 3 2
3 4 1
4 5 2
6
1 2 2
3 4 3
5 6 2
1 4 1
2 6 1
3 7 4

*/




  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值