2023大厂真题提交网址(含题解):
www.CodeFun2000.com(http://101.43.147.120/)
最近我们一直在将收集到的机试真题制作数据并搬运到自己的OJ上,供大家免费练习,体会真题难度。现在OJ已录入50+道2023年最新大厂真题,同时在不断的更新。同时,可以关注"塔子哥学算法"公众号获得每道题的题解。
题目大意:
给你 n n n个带有颜色的线段. m m m次询问,每次询问一个区间完全包含多少个不同颜色的线段.
题目思路:
离线:
类似HH的项链,但是变成区间问题了.
处理区间问题,利用扫描线的思想:我们可以对线段&区间按左端点排序。然后从后往前扫描,
遇到线段的左端点,则将对应右端点的位置的值+1.然后将该颜色上次出现的位置的值-1,取消贡献。
遇到查询时,直接树状数组查区间和.
原因显然:从后往前的过程中,对于一种颜色,我们只关心它当前最左边的出现(该位置最有可能有贡献).所以我们可以把该贡献记录在当前出现最左边的位置.
强制在线:主席树
若该问题强制在线了,那么我们就直接上主席树记录下每一个后缀树即可。由于这题涉及到离散化。那么就对左端点,二分大于等于L的位置.右端点二分最后一个小于等于R的位置即可.
主席树解法参考代码(已小范围暴力对拍):
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define pii pair<int,int>
#define pb push_back
#define mp make_pair
#define vi vector<int>
#define vll vector<ll>
#define fi first
#define se second
#define mid ((l + r) >> 1)
const int maxn = 4e5 + 5;
const int mod = 1e9 + 7;
int n , m;
struct Node{
int l , r , c;
bool operator < (const Node & a){
return l > a.l;
}
}q[maxn] , b[maxn];
vector<Node> a[maxn];
int dist[maxn] , tot;
int rt[maxn] , s[maxn << 4] , ls[maxn << 4] , rs[maxn << 4] , cnt;
void pushup (int t)
{
int tl = ls[t] , tr = rs[t];
s[t] = s[tl] + s[tr];
}
int add (int t , int l , int r , int p , int c)
{
int now = ++cnt;
ls[now] = ls[t];
rs[now] = rs[t];
if (l == r){
s[now] = s[t] + c;
return now;
}
if (p <= mid) ls[now] = add(ls[now] , l , mid , p , c);
else rs[now] = add(rs[now] , mid + 1 , r , p , c);
pushup(now);
return now;
}
int ask (int t , int l , int r , int L , int R)
{
if (L <= l && r <= R) return s[t];
int ans = 0;
if (L <= mid) ans += ask(ls[t] , l , mid , L , R);
if (R > mid) ans += ask(rs[t] , mid + 1 , r , L , R);
return ans;
}
int last[maxn];
int main()
{
ios::sync_with_stdio(false);
cin >> n >> m;
for (int i = 1 ; i <= n ; i++){
cin >> b[i].c >> b[i].l >> b[i].r;
dist[++tot] = b[i].l;
dist[++tot] = b[i].r;
}
for (int i = 1 ; i <= m ; i++){
cin >> q[i].l >> q[i].r;
dist[++tot] = q[i].l;
dist[++tot] = q[i].r;
}
// ÀëÉ¢»¯
sort(dist + 1 , dist + 1 + tot);
tot = unique(dist + 1 , dist + 1 + tot) - dist - 1;
for (int i = 1 ; i <= n ; i++){
b[i].l = lower_bound(dist + 1 , dist + 1 + tot , b[i].l) - dist;
b[i].r = lower_bound(dist + 1 , dist + 1 + tot , b[i].r) - dist;
a[b[i].l].push_back(b[i]);
}
for (int i = 1 ; i <= m ; i++){
q[i].l = lower_bound(dist + 1 , dist + 1 + tot , q[i].l) - dist;
q[i].r = lower_bound(dist + 1 , dist + 1 + tot , q[i].r) - dist;
}
//
sort(b + 1 , b + 1 + n);
memset(last , -1 , sizeof last);
for (int i = tot ; i >= 1 ; i--){
rt[i] = rt[i + 1];
for (auto g : a[i]){
if (last[g.c] == -1 || last[g.c] > g.r){
rt[i] = add(rt[i] , 1 , tot , g.r , 1);
if (last[g.c] != -1)
rt[i] = add(rt[i] , 1 , tot , last[g.c] , -1);
last[g.c] = g.r;
}
}
}
for (int i = 1 ; i <= m ; i++){
cout << ask(rt[q[i].l] , 1 , tot , q[i].l , q[i].r) << endl;
}
return 0;
}