POJ1436 线段树 区间更新

题中定义了什么叫做可见线段。所谓可见线段就是在给定的垂直与x轴的直线中,能够在两个直线之间连接一条平行线,并且这条平行线不与任何其他的直线相交。

WA一次,就是因为没有考虑到在建立点树的过程中会出现将 [1, 2] 和 [3, 4] 视为一条连接的直线,所以最后给坐标乘以一个2.

代码如下:

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <vector>
#include <map>
#define MAXN 8000
using namespace std;

struct Seq
{
int y1, y2, x;
bool operator < (Seq t) const
{
return x < t.x;
}
}e[MAXN+5];

struct
{
int l, r, who;
}seg[MAXN*8];

map<int,int>m[MAXN+5];

void build(int f, int l, int r)
{
int mid = l+r >> 1;
seg[f].l = l, seg[f].r = r;
seg[f].who = 0;
if (r > l)
{
build(f<<1, l, mid);
build(f<<1|1, mid+1, r);
}
}

void up(int f)
{
if (seg[f<<1].who == seg[f<<1|1].who)
seg[f].who = seg[f<<1].who;
else
seg[f].who = -1;
}

void modify(int f, int l, int r, int who, map<int, int>*m)
{
int mid = seg[f].l+seg[f].r >> 1;
if (seg[f].l == l && seg[f].r == r && (seg[f].who != -1 || r==l))
{
if (seg[f].who != -1 && seg[f].who != 0)
m[who][seg[f].who] = 1;
seg[f].who = who;

}
else if (seg[f].r > seg[f].l)
{
if (seg[f].who == 0)
{
seg[f<<1].who = seg[f<<1|1].who = seg[f].who;
seg[f].who = -1;
}
else if (seg[f].who != -1)
{
m[who][seg[f].who] = 1;
seg[f<<1].who = seg[f<<1|1].who = seg[f].who;
seg[f].who = -1;
}
if (r <= mid)
modify(f<<1, l, r, who, m);
else if (l > mid)
modify(f<<1|1, l, r, who, m);
else
{
modify(f<<1, l, mid, who, m);
modify(f<<1|1, mid+1, r, who, m);
}
up(f);
}
}

int main()
{
map<int,int>::iterator it1, it2;
int T, M, y1, y2, x, ans;
scanf("%d", &T);
build(1, 0, 2*MAXN);
while (T--)
{
ans = 0;
seg[1].who = 0;
scanf("%d", &M);
for (int i = 1; i <= M; ++i)
{
scanf("%d %d %d", &e[i].y1, &e[i].y2, &e[i].x);
e[i].y1 <<= 1, e[i].y2 <<= 1;
m[i].clear();
}
sort(e+1, e+1+M);
for (int i = 1; i <= M; ++i)
{
// printf("%d %d %d\n", e[i].y1, e[i].y2, e[i].x);
modify(1, e[i].y1, e[i].y2, i, m);
/* for (it = m[i].begin(); it != m[i].end(); ++it)
printf(".. %d ", it->first);
*/
}
for(int i = 1; i <= M; ++i) // 扫描整个表
{
for(it1 = m[i].begin(); it1 != m[i].end(); ++it1) // 遍历第i条线的可见线段
{
int k = it1->first; // 记录与其中的第k条线段可见
for(it2 = m[i].begin(); it2 != m[i].end(); ++it2) // 如果第k条线段与第i条线段有共同的可见线段的话 ans++
{
if (m[k].count(it2->first))
ans++;
}
}
}
printf("%d\n",ans);
}
return 0;
}





原文地址:https://www.cnblogs.com/Lyush/p/2385436.html