题意:
给出一系列竖直的线段, 给出上下两端点坐标和横坐标, 定义"水平可见"为两线段之间可以连一条水平线段, 使得该线段不与其他线段接触.
又定义"三条线段可组成三角形"为三条线段两两"水平可见".
问一组线段中一共可以组成多少三角形.
思路:
首先这个"可见"可以想到涂色覆盖问题, 纵向建立线段树. 可知横坐标只起到排序的作用, 并无影响.
因为是一层层添加, 所以就像求逆序数一样, 插入一条之前先询问, 再插入.
难点在于query.(之前理解不深之故...用着生疏)
离散化记得线段树是一个数代表一条线段, 因此要想表达分立的点, 需要扩大二倍留出点之间的空隙 !
#include <cstdio> #include <cstring> #include <algorithm> #include <vector> //1024K 157MS using namespace std; #define lson l, m, rt << 1 #define rson m + 1, r, rt << 1 | 1 const int MAXN = 8888; struct v_seg { int s, t, x; bool operator<(const v_seg& b) const { return x < b.x; } }ss[MAXN]; int col[MAXN<<2], hash[MAXN]; vector<int> v[MAXN]; void PushDown(int rt) { if(col[rt]!=-1) { col[rt<<1] = col[rt<<1|1] = col[rt]; col[rt] = -1; } } void update(int L, int R, int id, int l, int r, int rt) { if(L<=l && r<=R) { col[rt] = id; return; } PushDown(rt); int m = (l + r) >> 1; if(L<=m) update(L, R, id, lson); if(m<R) update(L, R, id, rson); } void query(int L, int R, int id, int l, int r, int rt) { if(col[rt]!=-1) { if(hash[col[rt]]!=id) {//query其实就是一个找纯色的过程, 找到了纯色, 其下的一段便确定; //没找到纯色, 就继续往下分. v[col[rt]].push_back(id);//统计该条线段都能够被那些线段看到 hash[col[rt]] = id;//索引是否不是第一次被同一条线段看到 } return; } if(l==r) return;//等于-1但又长度为1, 说明这里没有线段 PushDown(rt); int m = (l + r) >> 1; if(L<=m) query(L, R, id, lson); if(m<R) query(L, R, id, rson); } int main() { int i, j, k, t, n, T; scanf("%d",&T); while(T--) { memset(col, -1, sizeof(col)); memset(hash, -1, sizeof(hash)); scanf("%d",&n); for(i=0;i<n;i++) { scanf("%d%d%d",&ss[i].s,&ss[i].t,&ss[i].x); ss[i].s<<=1; ss[i].t<<=1; v[i].clear(); } sort(ss,ss+n); for(i=0;i<n;i++) { query(ss[i].s,ss[i].t,i,0,16000,1); update(ss[i].s,ss[i].t,i,0,16000,1); } int ans = 0; for(i=0;i<n;i++) for(j=0;j<v[i].size();j++) { k = v[i][j]; for(t=0;t<v[i].size();t++) for(int w=0;w<v[k].size();w++) if(v[k][w] == v[i][t]) ans++; } printf("%d\n",ans); } }
#include <cstdio> #include <cstring> #include <algorithm> #include <vector> //648K 110MS using namespace std; #define lson l, m, rt << 1 #define rson m + 1, r, rt << 1 | 1 const int MAXN = 8888;//但是不知道为什么这里写8005就不对...大概是需要的冗余比较多... struct v_seg { int s, t, x; bool operator<(const v_seg& b) const { return x < b.x; } }ss[MAXN]; int col[MAXN<<2],hash[MAXN]; struct pool { int to,pre; }p[MAXN<<2];//适当开 int head[MAXN],num; void add(int u, int v) { p[++num].to = v; p[num].pre = head[u]; head[u] = num; } void PushDown(int rt) { if(col[rt]!=-1) { col[rt<<1] = col[rt<<1|1] = col[rt]; col[rt] = -1; } } void update(int L, int R, int id, int l, int r, int rt) { if(L<=l && r<=R) { col[rt] = id; return; } PushDown(rt); int m = (l + r) >> 1; if(L<=m) update(L, R, id, lson); if(m<R) update(L, R, id, rson); } void query(int L, int R, int id, int l, int r, int rt) { if(col[rt]!=-1) { if(hash[col[rt]]!=id) { add(col[rt],id); hash[col[rt]] = id; } return; } if(l==r) return;//等于-1但又长度为1, 说明这里没有线段 PushDown(rt); int m = (l + r) >> 1; if(L<=m) query(L, R, id, lson); if(m<R) query(L, R, id, rson); } int main() { int i, n, T; scanf("%d",&T); while(T--) { memset(col, -1, sizeof(col)); memset(head, 0, sizeof(head)); memset(hash,-1,sizeof(hash)); num = 0; scanf("%d",&n); for(i=0;i<n;i++) { scanf("%d%d%d",&ss[i].s,&ss[i].t,&ss[i].x); ss[i].s<<=1; ss[i].t<<=1; } sort(ss,ss+n); for(i=0;i<n;i++) { query(ss[i].s,ss[i].t,i,0,16000,1); update(ss[i].s,ss[i].t,i,0,16000,1); } int ans = 0; for(int n1=0;n1<n;n1++) for(int i2=head[n1],n2;n2=p[i2].to,i2;i2=p[i2].pre) for(int i3=head[n1],n3;n3=p[i3].to,i3;i3=p[i3].pre) for(int i4=head[n2],n4;n4=p[i4].to,i4;i4=p[i4].pre) if(n3==n4) ans++; printf("%d\n",ans); } }