luogu P5816 [CQOI2010]内部白点
题面传送门
首先有一个结论就是不存在二次变换。
如果存在二次变换,那么二次变换那个点的至少一个方向会新出现一个点,但是要新出现一个点那个方向必定原来就存在一个点。所以不成立。
那么就可以从上到下做扫描线,当碰到一列最上面的点时给树状数组那个位置加一,最下面减一就好了。
代码实现:
#include<cstdio>
#include<vector>
#include<cstring>
#include<algorithm>
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
using namespace std;
int n,m,k,longge,now,last,f[200039],x[100039],y[100039],z,nows[200039],tots[200039],l,r,mid,s1[200039],s2[200039],minn[200039],maxn[200039];
long long ans;
vector<int> s[200039];
inline int ls(int x){
l=0;r=2*n+1;
while(l+1<r){
mid=(l+r)>>1;
if(nows[mid]<x) l=mid;
else r=mid;
}
return tots[r];
}
inline void get(int x,int y){while(x<=2*n) f[x]+=y,x+=x&-x;}
inline int find(int x){int ans=0;while(x) ans+=f[x],x-=x&-x;return ans;}
int main(){
// freopen("1.in","r",stdin);
register int i,j;
scanf("%d",&n);
for(i=1;i<=n;i++) scanf("%d%d",&x[i],&y[i]),nows[i*2-1]=x[i],nows[i*2]=y[i];
sort(nows+1,nows+2*n+1);
nows[0]=nows[1]-1;
for(i=1;i<=2*n;i++){
tots[i]=tots[i-1];
if(nows[i]!=nows[i-1]) tots[i]++;
}
memset(minn,0x3f,sizeof(minn));
memset(s1,0x3f,sizeof(s1));
for(i=1;i<=n;i++)x[i]=ls(x[i]),y[i]=ls(y[i]);
for(i=1;i<=n;i++) s[x[i]].push_back(y[i]);
for(i=1;i<=n;i++) maxn[x[i]]=max(maxn[x[i]],y[i]),minn[x[i]]=min(minn[x[i]],y[i]);
for(i=1;i<=n;i++) s1[y[i]]=min(s1[y[i]],x[i]),s2[y[i]]=max(s2[y[i]],x[i]);
for(i=1;i<=2*n;i++){
longge=s[i].size();
for(j=0;j<longge;j++) {
last=s[i][j];
if(s1[last]==i) get(last,1);
if(s2[last]==i) get(last,-1);
}
if(longge<2) continue;
for(j=0;j<longge;j++){
last=s[i][j];
if(i!=s2[last]) ans--;
}
ans+=find(maxn[i])-find(minn[i]-1);
//printf("%d\n",ans);
}
printf("%lld\n",ans+n);
}