题意:
就是给你n个线段,每个线段有个a,b,c,代表左端点,右端点,线段的颜色。现在问你每个线段距离其他颜色的线段中最小的距离是多少。如果有点交叉那么距离就是0。
思考:
- 当时看到距离那么肯定是要维护两个set,分别是存左端点和右端点的。然后发现距离必须是两个线段的颜色不一样,那么我就可以对每种颜色分类处理,先对某个颜色的线段处理,那么从set里删去这个颜色的东西,处理完之后,再放进去。复杂度也就是2×n×log(n)。
- 但是这样只能处理线段相离或者相交的,不能处理线段包含关系的。也就是对于[a,b]没法求别人包括它的情况。所以我就想了,能不能用线段树,对于某个点每有一个不同的颜色出现,那么这个点就加1。但是如果直接累加的话,相同颜色的线段之间还会重复,所以可能会加多,所以先用个经典的排序,求连续的区间就可以了。那么把这段连续的区间在线段树中加1就可以了。
- 但是我发现,线段的范围很大,1e9的范围。所以直接累加的话,线段树建立不了那么大,那么我就想了,感觉可以离散化,因为对于包含的那种关系,确实也是看点的大小,也就是离散化后包含关系不会改变。那么离散化后去线段树累加就可以了,复杂度n×log(n)。
- 那么最后对于这个线段[a,b],怎么判断是否这个里面有别的颜色的点呢?那么就是如果[a,b]之间某个点的值>=2就可以了,那我还要查询这段区间的最大值?其实不用,只要知道[a,b]这段区间的总和就好了,只要sum[a,b]>b-a+1,那么肯定有一个点是>=2的。
- 那么到此这个题目就结束了,感觉我真腻害,嘿嘿。其实就是把题目不要感觉太难,能有想法就想想,想想就出来了一般。
代码:
#include<bits/stdc++.h>
#define fi first
#define se second
#define pb push_back
#define db double
#define PII pair<int,int >
#define mem(a,b) memset(a,b,sizeof(a))
#define IOS std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
using namespace std;
const int mod = 1e9+7,inf = 1e9;
const int N = 4e5+10,M = 2010;
int T,n,m,k;
PII va[N];
int anw[N];
vector<int > vv;
multiset<int > sl,sr;
vector<pair<PII,int> > v[N];
struct seg_sum{
#define node_l node<<1
#define node_r node<<1|1
struct node{
int L,R;
int sum;
int laz;
}t[4*N];
void pushup(int node)
{
t[node].sum = t[node_l].sum+t[node_r].sum;
}
void pushdown(int node)
{
int laz = t[node].laz;
if(laz)
{
t[node_l].laz += laz;
t[node_l].sum += (t[node_l].R-t[node_l].L+1)*laz;
t[node_r].laz += laz;
t[node_r].sum += (t[node_r].R-t[node_r].L+1)*laz;
t[node].laz = 0;
}
}
void build(int node,int l,int r)
{
t[node].laz = t[node].sum = 0;
t[node].L = l,t[node].R = r;
if(l==r)
{
return ;
}
int mid = (l+r)>>1;
build(node_l,l,mid);build(node_r,mid+1,r);
pushup(node);
}
void update(int node,int l,int r,int value)
{
if(t[node].L>=l&&t[node].R<=r)
{
t[node].sum += (t[node].R-t[node].L+1)*value;
t[node].laz += value;
return ;
}
pushdown(node);
int mid = (t[node].L+t[node].R)>>1;
if(r<=mid) update(node_l,l,r,value);
else if(l>mid) update(node_r,l,r,value);
else update(node_l,l,mid,value),update(node_r,mid+1,r,value);
pushup(node);
}
int query(int node,int l,int r)
{
if(t[node].L>=l&&t[node].R<=r) return t[node].sum;
pushdown(node);
int mid = (t[node].L+t[node].R)>>1;
if(r<=mid) return query(node_l,l,r);
else if(l>mid) return query(node_r,l,r);
else return query(node_l,l,mid)+query(node_r,mid+1,r);
pushup(node);
}
}tsum;
void solve(int x)
{
for(auto t:v[x]) sl.erase(sl.find(t.fi.fi));
for(auto t:v[x]) sr.erase(sr.find(t.fi.se));
for(auto t:v[x])
{
auto idx = sl.lower_bound(t.fi.fi);
int minn = inf;
if(idx!=sl.end()) minn = min(minn,*idx-t.fi.se);
idx = sr.upper_bound(t.fi.se);
if(idx!=sr.begin())
{
idx--;
minn = min(minn,t.fi.fi-*idx);
}
anw[t.se] = max(0,minn);
}
for(auto t:v[x]) sl.insert(t.fi.fi);
for(auto t:v[x]) sr.insert(t.fi.se);
}
bool cmp(pair<PII,int> A,pair<PII,int> B)
{
if(A.fi.fi!=B.fi.fi) return A.fi.fi<B.fi.fi;
return A.fi.se<B.fi.se;
}
int get(int x)
{
return lower_bound(vv.begin(),vv.end(),x)-vv.begin()+1;
}
void futin(int x)
{
if(v[x].size()==0) return ;
for(auto &t:v[x])
{
t.fi.fi = get(t.fi.fi);
t.fi.se = get(t.fi.se);
}
sort(v[x].begin(),v[x].end());
int st = v[x][0].fi.fi,ed = v[x][0].fi.se;
for(auto t:v[x])
{
int l = t.fi.fi,r = t.fi.se;
if(l<=ed+1) ed = max(ed,r);
else
{
tsum.update(1,st,ed,1);
st = l,ed = r;
}
}
tsum.update(1,st,ed,1);
}
void init()
{
vv.clear();
sl.clear();sr.clear();
for(int i=0;i<=n;i++)
{
anw[i] = inf;
v[i].clear();
}
}
signed main()
{
IOS;
cin>>T;
while(T--)
{
cin>>n;
init();
for(int i=1;i<=n;i++)
{
int a,b,c;
cin>>a>>b>>c;
v[c].pb({
{
a,b},i});
sl.insert(a);sr.insert(b);
vv.pb(a);vv.pb(b);
}
sort(vv.begin(),vv.end());
vv.erase(unique(vv.begin(),vv.end()),vv.end());
tsum.build(1,1,vv.size());
for(int i=1;i<=n;i++) solve(i);
for(int i=1;i<=n;i++) futin(i);
for(int i=1;i<=n;i++)
{
for(auto t:v[i])
{
int sum = tsum.query(1,t.fi.fi,t.fi.se);
if(sum>t.fi.se-t.fi.fi+1) anw[t.se] = 0;
}
}
for(int i=1;i<=n;i++) cout<<anw[i]<<" ";
cout<<"\n";
}
return 0;
}
总结:
多多思考,不用觉得题目难,思考思考思路,一个不行再换,这样可以积累许多以后可能用到的操作。