• 可持久化线段树(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
  • 相关阅读:
    ASP.NET 页面间数据传递的方法
    ASP.NET中实现页面间数据传递的方法
    C# 连接SQL数据库
    C# 通过url地址获取页面内容
    JS弹窗带遮蔽的功能
    C# Code First 实例学习
    CS窗体程序数据列表分页
    关于RDLC报表打印预览界面显示页码问号的问题
    C#Dictionary键值对取值用法
    分别获取一个字符串中的字母和数字
  • 原文地址:https://www.cnblogs.com/wa007/p/10085587.html
Copyright © 2020-2023  润新知