zoukankan      html  css  js  c++  java
  • [BZOJ4237]稻草人

    BZOJ

    sol

    首先按横坐标排序。考虑CDQ,即考虑左边的点对右边的点的贡献。
    可以发现,左边的点可以对右边的点做贡献的只有上凸壳上面的点
    按照y坐标排序,如果是左边的点就更新上凸壳,如果是右边的点就在上凸壳上面二分,计算产生了多少的贡献。
    但是右边的点可能会对右边的点产生阻挡。
    可以对右边的点也维护一个横坐标递增的单调队列,每次在上凸壳上二分找的时候相当于有了一个界限。

    code

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    const int N = 200005;
    #define ll long long
    int gi()
    {
    	int x=0,w=1;char ch=getchar();
    	while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
    	if (ch=='-') w=0,ch=getchar();
    	while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    	return w?x:-x;
    }
    int n,q1[N],q2[N];ll ans;
    struct node{
    	int x,y;
    	bool operator < (const node &b) const
    		{return x<b.x;}
    }a[N],b[N];
    int find(int val,int l,int r)
    {
    	while (l<r)
    	{
    		int mid=l+r+1>>1;
    		if (a[q2[mid]].y<val) l=mid;
    		else r=mid-1;
    	}
    	return l;
    }
    void solve(int l,int r)
    {
    	if (l==r) return;
    	int mid=l+r>>1;
    	solve(l,mid);solve(mid+1,r);
    	int t1=0,t2=0;
    	for (int i=mid+1,j=l;i<=r;i++)
    	{
    		while (t1&&a[i].x<a[q1[t1]].x) --t1;//x坐标单调增 
    		q1[++t1]=i;
    		for (;a[j].y<a[i].y&&j<=mid;j++)
    		{
    			while (t2&&a[j].x>a[q2[t2]].x) --t2;//x坐标单调减 
    			q2[++t2]=j;
    		}
    		ans+=t2-find(a[q1[t1-1]].y,0,t2);
    	}
    	for (int i=l,j=mid+1,k=l;k<=r;)
    		b[k++]=(i<=mid&&(j>r||a[i].y<a[j].y))?a[i++]:a[j++];
    	for (int i=l;i<=r;i++) a[i]=b[i];
    }
    int main()
    {
    	n=gi();
    	for (int i=1;i<=n;i++)
    		a[i]=(node){gi()+1,gi()+1};
    	sort(a+1,a+n+1);
    	solve(1,n);
    	printf("%lld
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    游戏开发制作流程详细介绍
    成为群体领袖
    别人的,值得借鉴的经验
    linux下iptabes配置详解
    Oracle tnsnames.ora
    同时展多个物料BOM List
    Oracle判断是否为数字或数字型字符串
    linux上的vnc配置
    Oracle 中的正则函数
    如何将 backordered 的SO# 重新发运?
  • 原文地址:https://www.cnblogs.com/zhoushuyu/p/8424024.html
Copyright © 2011-2022 走看看