对于这种题目,基本上都是先枚举后维护信息。
自然的想到从小到大枚举横边或竖边,之后维护另一种边。
因为要区间计数,所以考虑树状数组,只要满足边穿过枚举边的都可以加入。
在固定最低边后往后枚举,计算组合数,并且注意删除不满足题意的边
#include<bits/stdc++.h> using namespace std; typedef long long ll; typedef pair<int,int> pll; const int N=2e5+10; const int inf=0x3f3f3f3f; int tr[N]; int lowbit(int x){ return x&-x; } void add(int x,int c){ int i; for(i=x;i<N;i+=lowbit(i)){ tr[i]+=c; } } ll sum(int x){ ll ans=0; for(int i=x;i;i-=lowbit(i)){ ans+=tr[i]; } return ans; } vector<pll> row[N]; vector<pll> col[N]; vector<int> num[N]; int main(){ ios::sync_with_stdio(false); int n; cin>>n; int i; for(i=1;i<=n;i++){ int x1,y1,x,y; cin>>x>>y>>x1>>y1; x+=5001; y+=5001; x1+=5001; y1+=5001; if(y==y1){ if(x>x1) swap(x,x1); row[y].push_back({x,x1}); } else{ if(y>y1) swap(y,y1); col[x].push_back({y,y1}); } } ll ans=0; for(int i=1;i<10004;i++){ for(auto x:row[i]){ for(int j=0;j<10004;j++) num[j].clear(); for(int j=x.first;j<=x.second;j++){ for(auto y:col[j]){ if(y.first<=i&&y.second>i){ num[y.second].push_back(j); add(j,1); } } } for(int j=i+1;j<10004;j++){ for(auto y:row[j]){ ll res=sum(y.second)-sum(y.first-1); ans+=res*(res-1)/2; } for(auto y:num[j]) add(y,-1); } } } cout<<ans<<endl; }