zoukankan      html  css  js  c++  java
  • BZOJ.4237.稻草人(CDQ分治 单调栈)

    题目链接

    考虑分治,消掉一维。
    把所有点按(y)排序,然后我们平行于x轴切一刀,将平面分成上下两部分,考虑上与下产生的答案(即右上角在上半部分,左下角在下半部分)。
    然后我们对上下两部分点分别按(x)排序。
    上面的点会受它前面(x,y)均比它小的点的影响。所以对上半部分我们需要维护(y_j)比当前小的最大的(x_j),可以用单调栈。
    而下半部分的点也会互相影响,我们发现可行点的(y)递减,它们都有可能(不受上面某点影响)成为答案。
    同样维护单调栈。对于上半部分内的限制,在单调栈中二分一个位置就好了。

    如图:

    计算1'时,下面的点2会被3,4覆盖;2'的计算会被1'影响;5会覆盖下面前面所有点......

    实现:
    每次CDQsort三遍太暴力了。虽然可过,但是常数大了(不止一点:5800kb 15748ms)。
    先按x排序,然后CDQ时按y归并排序,分成两部分。这样在同一部分的点一定还是按x排好序的。然后分治处理同一部分的点。但是这样不好找分割的位置,要离散化纵坐标,l,r表示y轴区间。
    或者可以先按y排序,处理完后把上下两部分点按x归并起来,这样同一部分的点的x是有序的,同时也保证前一部分的y都比后一部分的y小。

    //7368kb	3696ms
    #include <cstdio>
    #include <cctype>
    #include <algorithm>
    //#define gc() getchar()
    #define MAXIN 300000
    #define gc() (SS==TT&&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++)
    const int N=2e5+5;
    
    long long Ans;
    char IN[MAXIN],*SS=IN,*TT=IN;
    struct Point
    {
    	int x,y;
    }p[N],tmp[N],sk1[N],sk2[N];
    
    inline int read()
    {
    	int now=0;register char c=gc();
    	for(;!isdigit(c);c=gc());
    	for(;isdigit(c);now=now*10+c-'0',c=gc());
    	return now;
    }
    inline bool cmpx(const Point &a,const Point &b)
    {
    	return a.x<b.x;
    }
    inline bool cmpy(const Point &a,const Point &b)
    {
    	return a.y<b.y;
    }
    void CDQ(int l,int r)
    {
    	if(l==r) return;
    	int mid=l+r>>1;
    	CDQ(l,mid), CDQ(mid+1,r);
    
    	for(int now=l,top1=0,top2=0,i=mid+1; i<=r; ++i)
    	{
    		int xn=p[i].x,yn=p[i].y;
    		while(top1 && sk1[top1].y>=yn) --top1;
    		sk1[++top1]=p[i];
    
    		while(now<=mid && p[now].x<xn)
    		{
    			int yy=p[now].y;
    			while(top2 && sk2[top2].y<=yy) --top2;//其实题目已保证yi互不相同...
    			sk2[++top2]=p[now], ++now;
    		}
    
    		int xx=sk1[top1-1].x,L=1,R=top2,M,res=top2+1;
    		while(L<=R)
    		{
    			if(sk2[M=L+R>>1].x>=xx) res=M, R=M-1;//not mid...
    			else L=M+1;
    		}
    		Ans+=top2-res+1;
    	}
    	for(int i=l,a=l,b=mid+1; i<=r; ++i)
    		tmp[i]=((a<=mid&&p[a].x<p[b].x)||b>r)?p[a++]:p[b++];
    	for(int i=l; i<=r; ++i) p[i]=tmp[i];
    }
    
    int main()
    {
    	int n=read();
    	for(int i=1; i<=n; ++i) p[i]=(Point){read(),read()};
    	std::sort(p+1,p+1+n,cmpy);
    	sk1[0].x=sk2[0].x=-1, CDQ(1,n), printf("%lld
    ",Ans);
    
    	return 0;
    }
    
  • 相关阅读:
    互联网: 让网站强制使用https
    非常好用的原型设计软件Balsamiq Mockups
    11.Mapreduce实例——MapReduce自定义输出格式
    01.Mapreduce实例——去重
    08.Mapreduce实例——倒排索引
    06.Mapreduce实例——Reduce端join
    05.Mapreduce实例——Map端join
    07.Mapreduce实例——二次排序
    02.Mapreduce实例——求平均值
    10.Mapreduce实例——MapReduce自定义输入格式小
  • 原文地址:https://www.cnblogs.com/SovietPower/p/9671861.html
Copyright © 2011-2022 走看看