zoukankan      html  css  js  c++  java
  • P1856 [USACO5.5]矩形周长Picture

    P1856 [USACO5.5]矩形周长Picture

    $len$            $sum$              $num$             $flag\_l$ $flage\_r$分别表示该区间

    覆盖长度--整体覆盖次数--覆盖段数--左右端点是否覆盖

    将上下边按高度排序不断扫下来

    $num$是用来处理高度的

    inline void Update(LL now,LL l,LL r){
    	if(tree[now].sum){
    		tree[now].num=1,
    		tree[now].len=r-l+1,
    		tree[now].flag_l=tree[now].flag_r=1;
    	}else if(l==r){
    		tree[now].len=tree[now].num=tree[now].flag_l=tree[now].flag_r=0;
    	}else{
    		LL son0=now<<1,son1=son0|1;
    		tree[now].len=tree[son0].len+tree[son1].len,
    		tree[now].num=tree[son0].num+tree[son1].num;
    		if(tree[son0].flag_r&&tree[son1].flag_l)
    		    --tree[now].num;
    		tree[now].flag_l=tree[son0].flag_l,
    		tree[now].flag_r=tree[son1].flag_r;
    	}
    }

    现在来理解一下更新

    如果该区间至少覆盖了一次,显然只覆盖段数为$1$,注意线段树里长度是以分的

    如果没被覆盖

      $(1)$叶子节点,全部清空

      $(2)$长度$=$左右子树长度 覆盖段数也差不多,再加一下合并

    My complete code:

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<iostream>
    #include<string>
    using namespace std; 
    typedef long long LL;
    const LL maxn=1e5;
    inline LL Read(){
    	LL x=0,f=1; char c=getchar();
    	while(c<'0'||c>'9'){
    		if(c=='-') f=-1; c=getchar();
    	}
    	while(c>='0'&&c<='9'){
    		x=(x<<3)+(x<<1)+c-'0'; c=getchar();
    	}return x*f;
    }
    struct node{
    	LL l,r,h,val;
    }a[maxn];
    struct code{
    	LL len,sum,num,flag_l,flag_r;
    }tree[maxn];
    LL n,mi,mx,ans,num,last;
    inline bool cmp(node x,node y){
    	return x.h<y.h||(x.h==y.h&&x.val>y.val);
    }
    inline void Update(LL now,LL l,LL r){
    	if(tree[now].sum){
    		tree[now].num=1,
    		tree[now].len=r-l+1,
    		tree[now].flag_l=tree[now].flag_r=1;
    	}else if(l==r){
    		tree[now].len=tree[now].num=tree[now].flag_l=tree[now].flag_r=0;
    	}else{
    		LL son0=now<<1,son1=son0|1;
    		tree[now].len=tree[son0].len+tree[son1].len,
    		tree[now].num=tree[son0].num+tree[son1].num;
    		if(tree[son0].flag_r&&tree[son1].flag_l)
    		    --tree[now].num;
    		tree[now].flag_l=tree[son0].flag_l,
    		tree[now].flag_r=tree[son1].flag_r;
    	}
    }
    LL ci;
    void Add(LL now,LL l,LL r,LL lt,LL rt,LL v){
    	if(lt<=l&&rt>=r){
    		tree[now].sum+=v,
    		Update(now,l,r);
    		return;
    	}
    	LL mid=(l+r)>>1,son0=now<<1,son1=son0|1;
    	if(lt<=mid)
    	    Add(son0,l,mid,lt,rt,v);
    	if(rt>mid)
    	    Add(son1,mid+1,r,lt,rt,v);
    	Update(now,l,r);
    }
    int main(){
    	n=Read();
    	for(LL i=1;i<=n;++i){
    		LL x1=Read(),y1=Read(),x2=Read(),y2=Read();
    		mx=max(mx,max(x1,x2)),
    		mi=min(mi,min(x1,x2)),
    		a[++num]=(node){x1,x2,y1,1},
    		a[++num]=(node){x1,x2,y2,-1};
    	}
    	if(mi<=0){
    		for(LL i=1;i<=num;++i)
    		    a[i].l+=-mi+1,
    		    a[i].r+=-mi+1;
    		mx+=-mi;
    	}
    	sort(a+1,a+1+num,cmp);
    	for(LL i=1;i<=num;++i){
    		Add(1,1,mx,a[i].l,a[i].r-1,a[i].val);
    		while(a[i].h==a[i+1].h&&a[i].val==a[i+1].val){
    			++i,
    			Add(1,1,mx,a[i].l,a[i].r-1,a[i].val);
    		}
    		ans+=abs(last-tree[1].len),
    		last=tree[1].len,
    		ans+=2*tree[1].num*(a[i+1].h-a[i].h);
    	}
    	printf("%lld",ans);
    	return 0;
    }
    

      

  • 相关阅读:
    Android home键和back键区别
    装饰器模式
    对象的序列化
    构建器问题
    finnally的一些用法
    LinkedList ArrayList测试2
    LinkedList ArrayList测试
    meizu调试遇到 的问题
    java和c#通过esb服务互调用组件
    .NET平台常用的框架整理
  • 原文地址:https://www.cnblogs.com/y2823774827y/p/10131479.html
Copyright © 2011-2022 走看看