• NOI2009 区间


    题目链接:戳我

    60分部分分还是很好拿的,排序(按照左端点为第一关键字,右端点为第二关键字)之后一个(O(n^2)),暴力判交,更新最小值,就可以水过前12个测试点。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #include<vector>
    #define MAXN 100010
    #define inf 0x3f3f3f3f
    using namespace std;
    int n,m,ans=inf;
    struct Node{int l,r;}node[MAXN];
    inline bool cmp(struct Node x,struct Node y)
    {
        if(x.l==y.l) return x.r<y.r;
        return x.l<y.l;
    }
    int main()
    {
        #ifndef ONLINE_JUDGE
        freopen("ce.in","r",stdin);
        #endif
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++) 
        {
            scanf("%d%d",&node[i].l,&node[i].r);
            if(node[i].l==node[i].r) i--,n--;
        }
        sort(&node[1],&node[n+1],cmp);
        for(int i=1;i<=n;i++)
        {
            vector<int>v;
            int cnt=1;
            v.push_back(node[i].r-node[i].l);
            for(int j=1;j<=n;j++)
            {
                if(node[j].r<node[i].r||j==i||node[j].l>=node[i].r) continue;
                v.push_back(node[j].r-node[j].l);
                cnt++;
            }
            if(cnt<m) continue;
            sort(v.begin(),v.end());
            for(int i=0;i<v.size();i++)
            {
                int j=i+m-1;
                if(j>=v.size()) break;
                ans=min(ans,v[j]-v[i]);
            }
        }
        if(ans==inf) printf("-1
    ");
        else printf("%d
    ",ans);
        return 0;
    }
    

    现在我们来考虑正解——

    区间1e9有点大,先离散化一下。

    然后我们按照长度从小到大排序qwq,保证一个单调性,然后使用尺取法。给当前枚举到的线段所指区间+1,用线段树维护全局最大值,如果最大值==m,就可以用右指针所指线段的长度-左指针所指线段的长度更新答案了。如果当前全局最大值大于m,我们可以弹出原先的线段。

    什么是尺取法?就是维护两个指针一样的东西( l,r) ,每次确定区间的左端点,让(r)不断向右移动,直到满足条件停下,维护一下答案,直到(r>n) ]

    不过,注意一下,不要把node[i].l==node[i].r,省略掉qwqwq(不然会WA在UOJ上)

    代码如下:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #define MAXN 500010
    #define INF 2147483647
    using namespace std;
    
    int n,m,ans=INF,cnt;
    int pre[MAXN<<1];
    struct Node{int maxx,tag;}t[MAXN<<4];
    struct Node2{int l,r,len,id;}node[MAXN<<1];
    
    inline int ls(int x){return x<<1;}
    inline int rs(int x){return x<<1|1;}
    
    inline void push_up(int x){t[x].maxx=max(t[ls(x)].maxx,t[rs(x)].maxx);}
    
    inline bool cmp(struct Node2 x,struct Node2 y){return x.len<y.len;}
    
    inline void solve(int x,int k)
    {
        t[x].maxx+=k;
        t[x].tag+=k;
    }
    
    inline void push_down(int x)
    {
        if(t[x].tag)
        {
            solve(ls(x),t[x].tag);
            solve(rs(x),t[x].tag);
            t[x].tag=0;
        }
    } 
    
    inline void update(int x,int l,int r,int ll,int rr,int k)
    {
        if(ll<=l&&r<=rr) {solve(x,k);return;}
        int mid=(l+r)>>1;
        push_down(x);
        if(ll<=mid) update(ls(x),l,mid,ll,rr,k);
        if(mid<rr) update(rs(x),mid+1,r,ll,rr,k);
        push_up(x);
    }
    
    int main()
    {
        #ifndef ONLINE_JUDGE
        freopen("ce.in","r",stdin);
        #endif
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++) 
        {
            scanf("%d%d",&node[i].l,&node[i].r);
            node[i].len=node[i].r-node[i].l;
            node[i].id=i;
        }
        for(int i=1;i<=n;i++) pre[++cnt]=node[i].l,pre[++cnt]=node[i].r;
        sort(&pre[1],&pre[cnt+1]);
        cnt=unique(&pre[1],&pre[1+cnt])-pre-1;
        for(int i=1;i<=n;i++)
        {
            node[i].l=lower_bound(&pre[1],&pre[cnt+1],node[i].l)-pre;
            node[i].r=lower_bound(&pre[1],&pre[cnt+1],node[i].r)-pre;
        }
        sort(&node[1],&node[1+n],cmp);
        int head=0,tail=0;
        for(;;)
        {
            while(tail<n&&t[1].maxx<m)
            {
                ++tail;
                update(1,1,cnt,node[tail].l,node[tail].r,1);
            }
            if(t[1].maxx<m) break;
            while(head<n&&t[1].maxx>=m)
            {
                ++head;
                update(1,1,cnt,node[head].l,node[head].r,-1);
            }
            ans=min(ans,node[tail].len-node[head].len);
        }
        if(ans==INF) printf("-1
    ");
        else printf("%d
    ",ans);
        return 0;
    }
    

    注意这种离散化的题目!!!线段树要开8倍qwqwq
    要不然会RE掉三个点qwqwq

  • 相关阅读:
    图标字体IcoMoon 使用
    JS 寻找孩子并打印路径
    为什么要用on()而不直接使用click
    setTimeout 虚假的“异步”
    解决Ajax.BeginForm还是刷新页面的问题
    .net生成Excel,并下载
    C#判断文件是否正在被使用
    sql为数字添加千分位(也就是钱的格式)
    HotelIInventory项目小结
    一步一步实现FormsAuthentic验证登录
  • 原文地址:https://www.cnblogs.com/fengxunling/p/10513263.html
Copyright © 2020-2023  润新知