http://acm.hdu.edu.cn/showproblem.php?pid=5862
将竖线(y1 y2 x)拆为两个点 分别在y1 y2+1高度更新x位置 x轴用线段树维护 对于横线(x1 x2 y)就在y高度查询线段树上x1x2对应的区间 这时对应区间里面维护的就是当前高度的横线相交的竖线数量
using namespace std;
struct node1
{
    int x1,y1,x2,y2;
};
struct node2
{
    int tp;
    int x;
};
struct node3
{
    int x1;
    int x2;
};
node1 pre[100010];
vector <node2> point[200010];
vector <node3> seg[200010];
ll sum[800010];
int tmpx[200010],tmpy[200010];
int n,lenx,leny;
void update(int tar,ll val,int l,int r,int cur)
{
    int m;
    sum[cur]+=val;
    if(l==r) return;
    m=(l+r)/2;
    if(tar<=m) update(tar,val,l,m,2*cur);
    else update(tar,val,m+1,r,2*cur+1);
}
ll query(int pl,int pr,int l,int r,int cur)
{
    ll res;
    int m;
    if(pl<=l&&r<=pr) return sum[cur];
    res=0,m=(l+r)/2;
    if(pl<=m) res+=query(pl,pr,l,m,2*cur);
    if(pr>m) res+=query(pl,pr,m+1,r,2*cur+1);
    return res;
}
int main()
{
    node2 tmp2;
    node3 tmp3;
    ll ans;
    int t,i,j;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        lenx=0,leny=0;
        for(i=1;i<=n;i++)
        {
            scanf("%d%d%d%d",&pre[i].x1,&pre[i].y1,&pre[i].x2,&pre[i].y2);
            tmpx[++lenx]=pre[i].x1,tmpx[++lenx]=pre[i].x2;
            tmpy[++leny]=pre[i].y1,tmpy[++leny]=pre[i].y2;
        }
        sort(tmpx+1,tmpx+lenx+1);
        sort(tmpy+1,tmpy+leny+1);
        lenx=unique(tmpx+1,tmpx+lenx+1)-tmpx-1;
        leny=unique(tmpy+1,tmpy+leny+1)-tmpy-1;
        for(i=1;i<=n;i++)
        {
            pre[i].x1=lower_bound(tmpx+1,tmpx+lenx+1,pre[i].x1)-tmpx;
            pre[i].y1=lower_bound(tmpy+1,tmpy+leny+1,pre[i].y1)-tmpy;
            pre[i].x2=lower_bound(tmpx+1,tmpx+lenx+1,pre[i].x2)-tmpx;
            pre[i].y2=lower_bound(tmpy+1,tmpy+leny+1,pre[i].y2)-tmpy;
        }
        for(i=0;i<=200000;i++)
        {
            point[i].clear();
            seg[i].clear();
        }
        for(i=1;i<=n;i++)
        {
            if(pre[i].x1==pre[i].x2)
            {
                if(pre[i].y1>pre[i].y2) swap(pre[i].y1,pre[i].y2);
                tmp2.tp=1,tmp2.x=pre[i].x1;
                point[pre[i].y1].push_back(tmp2);
                tmp2.tp=2,tmp2.x=pre[i].x1;
                point[pre[i].y2+1].push_back(tmp2);
            }
            else
            {
                if(pre[i].x1>pre[i].x2) swap(pre[i].x1,pre[i].x2);
                tmp3.x1=pre[i].x1,tmp3.x2=pre[i].x2;
                seg[pre[i].y1].push_back(tmp3);
            }
        }
        memset(sum,0,sizeof(sum));
        ans=0;
        for(i=1;i<=leny;i++)
        {
            for(j=0;j<point[i].size();j++)
            {
                if(point[i][j].tp==1) update(point[i][j].x,1,1,lenx,1);
                else update(point[i][j].x,-1,1,lenx,1);
            }
            for(j=0;j<seg[i].size();j++)
            {
                ans+=query(seg[i][j].x1,seg[i][j].x2,1,lenx,1);
            }
        }
        printf("%lld\n",ans);
    }
    return 0;
}
                










