题意:
给出n个区间,每个区间有颜色。
m次询问,每次询问:这n个区间中所有被包含在[x,y]这一区间中的区间,它们的颜色是否取遍了[l,r]中的所有颜色。
题解:
先对所有线段的左右端点离散化。将所有线段按左端点排序。
然后对每个左端点x建一颗线段树。
线段树的下标是颜色,值为该颜色左端点大于等于x时的右端点最小值。
线段树维护区间最大值。
每次查询对应版本的区间颜色最大值。
然后从右往左更新线段树,后来的线段树可以直接继承前面线段树的答案。
查询的时候,先二分出x在离散化数组里的位置,查询最大值是否小于等于y即可。
时间复杂度(O(nlogn))。
#include<bits/stdc++.h>
using namespace std;
const int maxn=3e5+100;
const int M=maxn*40;
struct qnode {
int l,r;
int color;
bool operator < (const qnode &r) const {
return l<r.l;
}
}a[maxn];
int n,m,k;
int t[maxn];
int c[M];
int lson[M];
int rson[M];
int T[maxn];
int tot;
int build (int l,int r) {
int root=tot++;
c[root]=2e9;
if (l!=r) {
int mid=(l+r)>>1;
lson[root]=build(l,mid);
rson[root]=build(mid+1,r);
}
return root;
}
int up (int root,int l,int r,int p,int v) {
int newRoot=tot++;
if (l==p&&r==p) {
c[newRoot]=min(c[root],v);
return newRoot;
}
int mid=(l+r)>>1;
if (p<=mid) {
lson[newRoot]=up(lson[root],l,mid,p,v);
rson[newRoot]=rson[root];
}
if (p>mid) {
rson[newRoot]=up(rson[root],mid+1,r,p,v);
lson[newRoot]=lson[root];
}
c[newRoot]=max(c[lson[newRoot]],c[rson[newRoot]]);
return newRoot;
}
int query (int root,int l,int r,int L,int R) {
if (l>=L&&r<=R) return c[root];
int mid=(l+r)>>1;
int ans=0;
if (L<=mid) ans=max(ans,query(lson[root],l,mid,L,R));
if (R>mid) ans=max(ans,query(rson[root],mid+1,r,L,R));
return ans;
}
int main () {
scanf("%d%d%d",&n,&m,&k);
for (int i=1;i<=k;i++) scanf("%d%d%d",&a[i].l,&a[i].r,&a[i].color);
sort(a+1,a+k+1);
T[k+1]=build(1,n);
for (int i=k;i>=1;i--) {
//int tt=query(T[i+1],1,n,a[i].color,a[i].color);
T[i]=up(T[i+1],1,n,a[i].color,a[i].r);
}
while (m--) {
int aa,bb,x,y;
scanf("%d%d%d%d",&aa,&bb,&x,&y);
int l=1,r=k,p=-1;
while (l<=r) {
int mid=(l+r)>>1;
if (a[mid].l>=x) {
p=mid;
r=mid-1;
}
else {
l=mid+1;
}
}
if (p==-1) {
printf("no
"),fflush(stdout);
continue;
}
int tt=query(T[p],1,n,aa,bb);
if (tt<=y)
printf("yes
"),fflush(stdout);
else
printf("no
"),fflush(stdout);
}
}