codeforces 1190D-Tokitsukaze and Strange Rectangle
传送门:QAQQAQ
题意:给你在坐标轴上的N个点,问你用一条横线和两条竖线所划分出的不同点集的个数(不包括空集)
思路:在没想清楚的时候觉得这是一道水题:对于y轴排序,然后从下往上扫看上方x不同的个数s,ans+=(s+1)*s/2即可,但后来发现这样会重复考虑一些集合,即在当前点时这几个点关于x轴排序是连续的,删掉这个点后仍是连续的,所以我们在对于y轴扫描时要减去这些重复的集合
即我们对于Y轴排序,从上至下扫描,对于当前新加入的一层y,先加上(s+1)*s/2,再对于每一个x值寻找它们之间的空隙中原本存在了多少x,减去这些重复的集合tmp*(tmp+1)/2即可
在代码实现方面,我们用线段树维护x值l,r区间内现存在多少点,每当一层扫完,把原先不存在的x值update成1,若x存在就不要管它,注意sum维护的是当前不同的x轴的个数,而不是总点数
在更新答案方面,对于同一层的两个x之间query一下原有不同x值个数,减一下tmp*(tmp+1)/2即可,注意开头和结尾都要扫,而且线段树开到xn+1是为了防止越界
因为x,y<=1e9无法直接用线段树维护这么大一段区间,而n<=2e5,所以我们用常用技巧离散化一下即可
代码:(听说树状数组维护更方便,但我喜欢线段树啊……)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N=200005;
const ll inf=2000000000;
struct node{
ll x,y;
bool operator < (const node rhs) const{
if(y==rhs.y) return x<rhs.x;
return y>rhs.y;
}
}a[N];
ll n,x[N],y[N],mx=-inf,vis[N];
struct TREE{
ll sum;
}tree[N*4];
void push_up(TREE &fa,TREE ls,TREE rs)
{
fa.sum=ls.sum+rs.sum;
}
void build(ll x,ll l,ll r)
{
if(l==r)
{
tree[x].sum=0;
return;
}
ll mid=(l+r)>>1;
build(x+x,l,mid);
build(x+x+1,mid+1,r);
push_up(tree[x],tree[x+x],tree[x+x+1]);
}
void update(ll x,ll l,ll r,ll pos)
{
if(l==r)
{
tree[x].sum=1;
return;
}
ll mid=(l+r)>>1;
if(pos>mid) update(x+x+1,mid+1,r,pos);
if(pos<=mid) update(x+x,l,mid,pos);
push_up(tree[x],tree[x+x],tree[x+x+1]);
}
ll query(ll x,ll l,ll r,ll L,ll R)
{
if(L>R) return 0;
if(L<=l&&r<=R) return tree[x].sum;
ll mid=(l+r)>>1;
if(mid>=R) return query(x+x,l,mid,L,R);
if(mid<L) return query(x+x+1,mid+1,r,L,R);
return query(x+x,l,mid,L,R)+query(x+x+1,mid+1,r,L,R);
}
int main()
{
scanf("%lld",&n);
for(ll i=1;i<=n;i++)
{
scanf("%lld%lld",&a[i].x,&a[i].y);
x[i]=a[i].x; y[i]=a[i].y;
}
sort(x+1,x+n+1); sort(y+1,y+n+1);
ll xn=unique(x+1,x+n+1)-x-1;
ll yn=unique(y+1,y+n+1)-y-1;
for(ll i=1;i<=n;i++)
{
a[i].x=lower_bound(x+1,x+xn+1,a[i].x)-x;
a[i].y=lower_bound(y+1,y+yn+1,a[i].y)-y;
}
sort(a+1,a+n+1);
build(1,1,xn+1);
ll ans=0,sum=0;
ll beg=1,now=1;
memset(vis,0,sizeof(vis));
while(beg<=n)
{
ll pre=0;
while(a[beg].y==a[now].y&&now<=n)
{
ll tmp=query(1,1,xn+1,pre+1,a[now].x-1);
ans-=tmp*(tmp+1)/2;
pre=a[now].x;
now++;
}
ll tmp=query(1,1,xn+1,pre+1,xn);
ans-=tmp*(tmp+1)/2;
while(beg<now)
{
if(!vis[a[beg].x])
{
sum++;
vis[a[beg].x]=1;
update(1,1,xn+1,a[beg].x);
}
beg++;
}
ans+=(sum+1)*sum/2;
}
cout<<ans<<endl;
return 0;
}
转载于//www.cnblogs.com/Forever-666/p/11253460.html
还没有评论,来说两句吧...