• hdu 1828 && pku 1177 Picture


    这困扰我N久的题目,终于过了。

    求N个矩形的周长并,一开始觉得太遥不可及了,感觉好复杂 ,总想先搞懂计算的方法,再看大牛的方法,可是N久之后,对那个方法还是一知半解;

    今天结合了代码还有下面俩副图之后,突然觉得豁然开朗啦,自己敲了一遍代码……

    重点:我觉得,最重要的就是理解下面三个式子了,理解了之后,就知道该怎么建立线段树了;

       ans+=num[1]*(ss[i+1].x-ss[i].x);(横边)
       ans+=abs(len[1]-last);(竖边)
       last=len[1];

    对所有的竖边按照x值从小到排序,之后按顺序插入线段树;

    ans累加的是最终结果,num[1]是整个区间内连续的线段数(将竖边投影到y轴的区间),len[1]表示整个区间内被覆盖的长度,而last保存的是上一次的len[1];

    也就是说,从左往右在每一次插入一条边后,周长并的累加值==新增的横边+新增的竖边。

    我们可以发现,插入一条边之后,新增的横边的树木等于区间内连续线段的数目*新增横边的长度,新增的竖边等于插入前后覆盖长度的差值。

    结合下面的图片我们会发现:插入一条出边之后,其实等同于删除该矩形对应的入边。对应下图,此时也就出现了不连续的线段了。横边也相应增加了。

    注意:不需要重复建树,因为插入所有边后,相对的也将树中可能产生影响的域给清空了。

     

    结合代码吧:

     

    #include<iostream>
    #include<algorithm>
    #define maxn 20010
    using namespace std;
    struct node
    {
    	int x,y1,y2,s;
    	node(int a=0,int b=0,int c=0,int d=0):x(a) , y1(b) , y2(c) , s(d) {}
    	friend bool operator <(const node a,const node b)
    	{
    		return a.x<b.x;
    	}
    };
    node ss[maxn>>1];//保存矩形的边,其中s表示该边为入边还是出边
    bool cmp(node a,node b)
    {
    	return a.x<b.x;
    }
    bool lb[maxn<<2],rb[maxn<<2];
    int cnt[maxn<<2],len[maxn<<2],num[maxn<<2];
    //len[]表示该区间被覆盖的总长度
    //num[]表示该区间内连续的线段数目
    //cnt[]表示该区间被覆盖的次数
    void PushUp(int k,int s,int t)
    {
    	if(cnt[k])
    	{
    		lb[k]=rb[k]=1;
    		num[k]=2;
    		len[k]=t-s+1;
    	}
    	else if(s==t)
    		lb[k]=rb[k]=num[k]=len[k]=0;
    	else {
    		num[k]=num[k<<1]+num[k<<1 |1];
    		len[k]=len[k<<1]+len[k<<1 |1];
    		lb[k]=lb[k<<1];
    		rb[k]=rb[k<<1|1];
    		if(rb[k<<1] && lb[k<<1 |1])//左右子区间的有一个线段相连
    			num[k]-=2;
    	}
    }
    void update(int l,int r,int c,int s,int t,int k)
    {
    	if(l<=s && t<=r)
    	{
    		cnt[k]+=c;//插边或删边
    		PushUp(k,s,t);
    		return ;
    	}
    	int kl=k<<1,kr=kl+1,mid=(s+t)>>1;
    	if(l<=mid)
    		update(l,r,c,s,mid,kl);
    	if(r>mid)
    		update(l,r,c,mid+1,t,kr);
    	PushUp(k,s,t);
    }
    int main()
    {
    	int a,b,c,d,n;
    	int miny,maxy;
    	while(scanf("%d",&n)==1)
    	{
    		int m=0;
    		miny=10000;
    		maxy=-10000;
    		for(int i=0;i<n;i++)
    		{
    			scanf("%d %d %d %d",&a,&b,&c,&d);
    			miny=min(miny,b);
    			maxy=max(maxy,d);
    			ss[m++]=node(a,b,d,1);
    			ss[m++]=node(c,b,d,-1);
    		}
    		sort(ss,ss+m);
    		int ans=0,last=0;
    		for(int i=0;i<m;i++)
    		{
    			if(ss[i].y1<ss[i].y2)
    			update(ss[i].y1,ss[i].y2-1,ss[i].s,miny,maxy-1,1);
    			ans+=num[1]*(ss[i+1].x-ss[i].x);
    			ans+=abs(len[1]-last);
    			last=len[1];
    		}
    		printf("%d\n",ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    tars framework 源码解读(五) framework 部分章节。PropertyServer,StatServer上报统计服务
    tars framework 源码解读(五) framework 部分章节。NotifyServer 通知服务
    mysql之 percona-xtrabackup 2.4.7安装(热备工具)
    年轻
    C语言整型数据(整数)
    【转】想象5年后的你
    MyBatis学习总结(二)——MyBatis核心配置文件与输入输出映射
    CSS3——前端预处理技术(Less、Sass、CoffeeScript、TypeScript)
    HTML(三)——本地存储
    HTML5(二)——特殊符号、新增属性、表单重写属性、
  • 原文地址:https://www.cnblogs.com/nanke/p/2198044.html
Copyright © 2020-2023  润新知