可持久化线段树(cf1080F)

大佬博客 https://www.cnblogs.com/zinthos/p/3899565.html

题目:https://codeforces.com/problemset/problem/1080/F

题目大意:

  给你k个线段,每个线段属于一个集合(n),每次查询a,b,x,y,求[a,b]的集合是否都存在一个区间[l,r]使得l<=x&&r>=y

解法:

  题目等同于,对于[a,b]中的每一个集合,左端点大于x的线段中最小的右端点,的最大值是否<=y;

  对线段排序(根据左端点l值),根据线段左端点值l由大到小依次插入更新线段树(插入时维护最小值),线段树维护[1,n]上的最大的区间右端点值(所有的 集合的最小右端点 的最大值),每次更新需要复制的节点数最多为log个,端点数最多为nlogn

#include<bits/stdc++.h>
using namespace std;
#define freread freopen("input.txt","r",stdin);
#define frewrite freopen("output.txt","w",stdout);
typedef long long ll;
const int maxn=3e5+7;
const int inf=(1LL<<31)-1;
int n,m,k,ar[maxn];
struct node{
    int l,r,mx;
}no[6000001];
struct data{
    int l,r,v;
    operator < (const data& other){
        return l<other.l;
    }
    void prin(){
        cout<<"da = "<<l<<" "<<r<<" "<<v<<endl;
    }
}da[maxn];
int root[maxn],tot=0;
void newNode(int& u,int p){
    u=++tot;
    no[u]=no[p];
}
void push(int x){
    no[x].mx=max(no[no[x].l].mx , no[no[x].r].mx);
}
void build(int l,int r,int &o){
    newNode(o,0);
    if(l==r){
        no[o].mx=inf;
        return ;
    }
    int mid=l+r>>1;
    build(l,mid,no[o].l);
    build(mid+1,r,no[o].r);
    push(o);
}
void ensert(int l,int r,int& o,int pre,int a,int b){
    newNode(o,pre);
    if(l==r){
        no[o].mx=min(no[o].mx, b);
        return ;
    }
    int mid=l+r>>1;
    if(a<=mid)ensert(l,mid,no[o].l,no[o].l,a,b);
    else ensert(mid+1,r,no[o].r,no[o].r,a,b);
    push(o);
}
int que(int l,int r,int o,int a,int b){
    if(l==a && r==b){
        return no[o].mx;
    }
    int mid=l+r>>1;
    int ans=0;
    if(a<=mid)ans=max(ans, que(l,mid,no[o].l,a,min(b,mid)));
    if(b>mid)ans=max(ans, que(mid+1,r,no[o].r,max(a,mid+1),b));
    return ans;
}
int findpos(int x){
    int l=1,r=k+1;
    while(l<r){
        int mid=(l+r)>>1;
        if(da[mid].l>=x)r=mid;
        else l=mid+1;
    }
    return l;
}

int main()
{
    scanf("%d%d%d",&n,&m,&k);
    for(int i=1;i<=k;i++){
        scanf("%d%d%d",&da[i].l,&da[i].r,&da[i].v);
    }
    sort(da+1,da+k+1);
    build(1,n,root[k+1]);
    for(int i=k;i>=1;i--){
        ensert(1,n,root[i],root[i+1],da[i].v,da[i].r);
    }
    da[k+1].l=1e9+1;
    while(m--){
        int a,b,x,y;
        scanf("%d%d%d%d",&a,&b,&x,&y);
        int ans=que(1,n,root[findpos(x)],a,b);
        puts(ans<=y? "yes":"no");
        fflush(stdout);
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/wa007/p/10085587.html