• BZOJ 2731 Luogu P3219 [HNOI2012]三角形覆盖问题 (扫描线)


    题目链接: (bzoj)https://www.lydsy.com/JudgeOnline/problem.php?id=2731

    (luogu)https://www.luogu.org/problemnew/show/P3219

    题解: 先讲一种复杂度明显不对但是本题数据跑得很快的做法: 先按底边(y)坐标排序,从下往上扫,每扫到一行链表维护当前的所有区间,另外再开个数组记录每个横坐标被覆盖的次数。复杂度(O(sum d_i))

    然后ckw巨佬的做法: 按底边(y)坐标排序,找出所有三角形的最左点和最右点的(x)坐标作为关键点,按(x)坐标从左到右扫每一个关键点。

    对于每相邻两个关键点之间的区间,找到所有包含它的三角形,那么每个三角形在此区间内一定是一个梯形,分类讨论(注意到我们已经按底边纵坐标排好序了)

    如果上面的梯形顶端比下面的梯形顶端低,那么什么也不用做;

    如果上面的梯形底端比下面的梯形顶端高,那么直接把下面梯形面积加入答案然后用上面梯形取代即可;

    否则i,如果上面的梯形的底边比下面的梯形的右上点低,那么把两个梯形拼成一个梯形即可;

    如果上面的梯形的底边比下面梯形的右上点高,那么计算下面梯形不被上面覆盖的面积(一个矩形减一个等腰直角三角形)加入答案,然后用上面梯形取代。

    时间复杂度(O(n^2))

    (ckw: “这种SB题有什么做的必要么”)

    代码

    做法一

    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<cassert>
    #include<algorithm>
    #define llong long long
    using namespace std;
    
    const int N = 1e4;
    const int C = 2e6;
    struct Point
    {
    	llong x,y;
    	Point() {}
    	Point(llong _x,llong _y) {x = _x,y = _y;}
    };
    struct Triangle
    {
    	Point x; llong d;
    	bool operator <(const Triangle &arg) const {return x.y<arg.x.y;}
    };
    struct Element
    {
    	int lb,rb,nxt,prv;
    } cur[N+3];
    Triangle a[N+3];
    int num[C+3]; //±»¸²¸Ç´ÎÊý 
    int n,cnt;
    
    int main()
    {
    	scanf("%d",&n);
    	for(int i=1; i<=n; i++)
    	{
    		scanf("%lld%lld%lld",&a[i].x.x,&a[i].x.y,&a[i].d);
    	}
    	sort(a+1,a+n+1);
    	int j = 0; llong ans = 0ll,tmp = 0ll;
    	for(int i=0; i<=C; i++)
    	{
    		//±éÀúÁ´±í£¬É¾µô¸ÃɾµÄ 
    		for(int k=cur[0].nxt; k!=0; k=cur[k].nxt)
    		{
    			num[cur[k].rb]--; if(num[cur[k].rb]==0) tmp--;
    			cur[k].rb--; if(cur[k].lb>=cur[k].rb) {cur[cur[k].prv].nxt = cur[k].nxt; cur[cur[k].nxt].prv = cur[k].prv;}
    		}
    		ans += tmp;
    		//¼ÓÈëÒÔ´ËΪµ×±ßµÄÈý½ÇÐÎ 
    		while(j<n && a[j+1].x.y==i)
    		{
    			j++;
    			if(a[j].d==0) continue;
    			for(int k=a[j].x.x+1; k<=a[j].x.x+a[j].d; k++)
    			{
    				num[k]++; if(num[k]==1) tmp++;
    			}
    			cnt++; cur[cnt].prv = cur[0].prv; cur[cur[cnt].prv].nxt = cnt; cur[0].prv = cnt; cur[cnt].nxt = 0;
    			cur[cnt].lb = a[j].x.x; cur[cnt].rb = a[j].x.x+a[j].d;
    		}
    		ans += tmp;
    	}
    	for(int i=0; i<=C; i++) assert(num[i]==0);
    	printf("%lld",ans/2); if(ans&1) printf(".5"); else printf(".0");
    	return 0;
    }
    

    做法二

    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<cassert>
    #include<algorithm>
    #include<vector>
    #define llong long long
    using namespace std;
    
    const int N = 1e4;
    const int C = 2e6;
    struct Point
    {
    	llong x,y;
    	Point() {}
    	Point(llong _x,llong _y) {x = _x,y = _y;}
    };
    struct Triangle
    {
    	Point x; llong d;
    	bool operator <(const Triangle &arg) const {return x.y<arg.x.y;}
    };
    Triangle a[N+3];
    vector<int> ky;
    int n,cnt;
    
    llong sqr(llong x) {return x<0ll ? 0ll : x*x;}
    
    int main()
    {
    	scanf("%d",&n);
    	for(int i=1; i<=n; i++)
    	{
    		scanf("%lld%lld%lld",&a[i].x.x,&a[i].x.y,&a[i].d);
    		if(a[i].d==0) continue;
    		ky.push_back(a[i].x.x); ky.push_back(a[i].x.x+a[i].d);
    	}
    	sort(ky.begin(),ky.end());
    	ky.erase(unique(ky.begin(),ky.end()),ky.end());
    	sort(a+1,a+n+1);
    	llong ans = 0ll;
    	for(int i=1; i<ky.size(); i++)
    	{
    		int dn = 0,up = 0; //upl
    		for(int j=1; j<=n; j++)
    		{
    			if(a[j].d==0) continue;
    			if(a[j].x.x<=ky[i-1] && a[j].x.x+a[j].d>=ky[i])
    			{
    				if(dn==0 && up==0) {dn = a[j].x.y; up = a[j].x.y+a[j].d-(ky[i-1]-a[j].x.x);}
    				else
    				{
    					if(a[j].x.y>up)
    					{
    						ans += 2ll*(up-dn)*(ky[i]-ky[i-1])-sqr(ky[i]-ky[i-1]);
    						dn = a[j].x.y; up = a[j].x.y+a[j].d-(ky[i-1]-a[j].x.x);
    					}
    					else if(a[j].x.y+a[j].d-(ky[i-1]-a[j].x.x)>up)
    					{
    						ans += 2ll*(ky[i]-ky[i-1])*(a[j].x.y-dn);
    						if(a[j].x.y>up-(ky[i]-ky[i-1])) {ans -= sqr(a[j].x.y-(up-(ky[i]-ky[i-1])));}
    						dn = a[j].x.y; up = a[j].x.y+a[j].d-(ky[i-1]-a[j].x.x);
    					}
    				}
    			}
    		}
    		if(up==0 && dn==0);
    		else {ans += 2ll*(up-dn)*(ky[i]-ky[i-1])-sqr(ky[i]-ky[i-1]);}
    	}
    	printf("%lld",ans/2); if(ans&1) printf(".5"); else printf(".0");
    	return 0;
    }
    
  • 相关阅读:
    使用git管理github项目
    router 跳转页面
    JS中[object object]怎么取值
    微信授权获取code
    闭包
    css属性clear
    javaScript循环
    css属性position
    跨域
    浅析JS内存 一
  • 原文地址:https://www.cnblogs.com/suncongbo/p/11128253.html
Copyright © 2020-2023  润新知