题目链接
Codeforces Round #826 (Div. 3)
F.Multi-Colored Segments
Multi-Colored Segments
题面翻译
给定一维数轴上 \(n\) 条线段,每条线段都有给定的颜色 \(c_i\)。
对于每个 \(i\),请求出:
\[\min_{c_j\ne c_i}dis(i,j) \]其中 \(dis(i,j)\) 表示线段 \(i,j\) 之间的距离,特别地,有相交(包括端点)的两条线段之间的距离定义为 \(0\)。
\(T\) 组询问,\(\sum n \leq 2\times 10^5\),线段两端点 \(1\leq l,r \leq 10^9,1\leq c\leq n\)。
样例 #1
样例输入 #1
9
3
1 2 1
3 4 1
5 6 2
2
100000000 200000000 1
900000000 1000000000 2
5
1 2 1
2 3 2
3 4 3
4 5 4
5 6 5
5
1 5 1
4 9 2
1 2 1
8 9 2
5 7 3
2
1 100 2
10 90 1
3
1 1 1
10 10 2
1000000000 1000000000 3
3
3 4 1
2 5 1
1 6 2
6
5 6 2
11 12 3
7 8 2
3 4 2
1 2 1
9 10 2
2
1 3 1
2 3 2
样例输出 #1
3 1 1
700000000 700000000
0 0 0 0 0
0 0 2 1 0
0 0
9 9 999999990
0 0 0
3 1 3 1 1 1
0 0
样例 #2
样例输入 #2
4
8
11 16 7
12 15 7
2 5 8
17 22 5
1 8 8
19 23 8
16 16 6
6 7 5
9
1 4 3
5 11 1
8 11 3
1 10 1
2 11 1
1 10 4
3 11 1
5 7 1
1 11 1
9
25 25 1
26 26 1
24 24 2
13 14 2
12 16 2
17 18 1
19 19 1
24 27 2
24 27 1
9
15 18 1
20 22 2
13 22 2
13 22 2
3 13 2
6 10 2
3 6 2
19 24 2
22 24 2
样例输出 #2
0 1 1 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 3 1 1 3 0 0
0 2 0 0 2 5 9 1 4
解题思路
线段树,二分
对于每条线段来分析,总共三种情况:与其他线段相交、左端点与其他线段右端点最近、右端点与其他线段左端点最近,对于后面两种情况,可以先将所有线段的左右端点分别放入 multiset
中,然后每次查询前先将所有颜色相等的点删除再二分即可,对于第一种情况,同理,先将所有线段端点内的区间加一,然后查询某种颜色时再将该颜色所有相关区间减一,在查询对应区间总和,和大于 \(0\) 说明有交集
- 时间复杂度:\(O(nlogn)\)
代码
// Problem: F. Multi-Colored Segments
// Contest: Codeforces - Codeforces Round #826 (Div. 3)
// URL: https://codeforces.com/contest/1741/problem/F
// Memory Limit: 256 MB
// Time Limit: 3000 ms
//
// Powered by CP Editor (https://cpeditor.org)
// %%%Skyqwq
#include <bits/stdc++.h>
// #define int long long
#define help {cin.tie(NULL); cout.tie(NULL);}
#define pb push_back
#define fi first
#define se second
#define mkp make_pair
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; }
template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; }
template <typename T> void inline read(T &x) {
int f = 1; x = 0; char s = getchar();
while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
x *= f;
}
const int N=2e5+5,inf=0x3f3f3f3f;
int t,n,res[N];
struct A
{
int l,r,c,id;
}a[N];
struct Tr
{
int l,r,add,sum;
}tr[N<<3];
vector<A> b[N];
vector<int> xs;
int find(int x)
{
return lower_bound(xs.begin(),xs.end(),x)-xs.begin()+1;
}
void pushup(int p)
{
tr[p].sum=tr[p<<1].sum+tr[p<<1|1].sum;
}
void pushdown(int p)
{
if(tr[p].add)
{
tr[p<<1].sum+=tr[p].add*(tr[p<<1].r-tr[p<<1].l+1);
tr[p<<1|1].sum+=tr[p].add*(tr[p<<1|1].r-tr[p<<1|1].l+1);
tr[p<<1].add+=tr[p].add,tr[p<<1|1].add+=tr[p].add;
tr[p].add=0;
}
}
void build(int p,int l,int r)
{
tr[p]={l,r,0,0};
if(l==r)return ;
int mid=l+r>>1;
build(p<<1,l,mid),build(p<<1|1,mid+1,r);
pushup(p);
}
void add(int p,int l,int r,int x)
{
if(l<=tr[p].l&&tr[p].r<=r)
{
tr[p].sum+=x*(tr[p].r-tr[p].l+1);
tr[p].add+=x;
return ;
}
pushdown(p);
int mid=tr[p].l+tr[p].r>>1;
if(l<=mid)add(p<<1,l,r,x);
if(r>mid)add(p<<1|1,l,r,x);
pushup(p);
}
int ask(int p,int l,int r)
{
if(l<=tr[p].l&&tr[p].r<=r)return tr[p].sum;
pushdown(p);
int mid=tr[p].l+tr[p].r>>1,res=0;
if(l<=mid)res+=ask(p<<1,l,r);
if(r>mid)res+=ask(p<<1|1,l,r);
return res;
}
int main()
{
for(cin>>t;t;t--)
{
cin>>n;
xs.clear();
for(int i=1;i<=n;i++)
{
cin>>a[i].l>>a[i].r>>a[i].c;
xs.pb(a[i].l),xs.pb(a[i].r);
a[i].id=i;
b[i].clear(),res[i]=inf;
}
sort(xs.begin(),xs.end());
xs.erase(unique(xs.begin(),xs.end()),xs.end());
build(1,1,xs.size());
multiset<int> s[2];
for(int i=1;i<=n;i++)
{
a[i].l=find(a[i].l),a[i].r=find(a[i].r);
s[0].insert(a[i].l),s[1].insert(a[i].r);
b[a[i].c].pb(a[i]);
add(1,a[i].l,a[i].r,1);
}
for(int i=1;i<=n;i++)
{
for(auto j:b[i])
{
int l=j.l,r=j.r;
add(1,l,r,-1);
s[0].erase(s[0].lower_bound(l)),s[1].erase(s[1].lower_bound(r));
}
for(auto j:b[i])
{
int l=j.l,r=j.r,id=j.id;
if(ask(1,l,r))res[id]=0;
else
{
auto it=s[0].lower_bound(r);
if(it!=s[0].end())
res[id]=min(res[id],xs[*it-1]-xs[r-1]);
it=s[1].upper_bound(l);
if(it!=s[1].begin()&&s[1].size())
{
it--;
res[id]=min(res[id],xs[l-1]-xs[*it-1]);
}
}
}
for(auto j:b[i])
{
int l=j.l,r=j.r;
add(1,l,r,1);
s[0].insert(l),s[1].insert(r);
}
}
for(int i=1;i<=n;i++)cout<<res[i]<<' ';
puts("");
}
return 0;
}
标签:11,10,int,线段,Codeforces,端点,xs,Div,826
From: https://www.cnblogs.com/zyyun/p/16843320.html