• 【HDU 4343】Interval query(倍增)


    BUPT2017 wintertraining(15) #8D

    题意

    给你x轴上的N个线段,M次查询,每次问你[l,r]区间里最多有多少个不相交的线段。(0<N, M<=100000)
    限时15000 MS

    题解

    如果不看限时,当作是1000MS的话= =,那么可以用倍增来做。
    先按右端点排序。
    可以去掉一下包含了其它区间的区间,可以优化一点点。
    用 f[i][j] 表示 i 节点下 (2^n) 个不相交的线段下标。
    预处理出 f 数组。
    查询的时候,左端点用二分,然后右端点用倍增来找。
    实际上不用倍增,也可以卡时间过。

    代码

    780ms

    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    #define N 100005
    using namespace std;
    struct Seg{
        int s,e;
        bool operator < (const Seg &b) const{
        	return e<b.e||e==b.e&&s>b.s;
        }
    }seg[N];
    int n,m;
    int f[N][32];
    int main(){
    	while(~scanf("%d %d", &n, &m)){
    		for(int i=0;i<n;++i)
    			scanf("%d %d", &seg[i].s, &seg[i].e);
    		memset(f,-1,sizeof f);
    		sort(seg,seg+n);
    		int nn=0;
    		for(int i=1;i<n;++i)
    			if(seg[nn].s<seg[i].s)
    				seg[++nn]=seg[i];
    		++nn;
    		for(int i=0;i<nn;++i){
    			f[i][0]=i+1;
    			while(f[i][0]<nn&&seg[f[i][0]].s<seg[i].e)++f[i][0];
    			if(f[i][0]==nn)f[i][0]=-1;
    		}
    		for(int j=0;j<30;++j)
    		for(int i=0;i<nn;++i)
    			if(f[i][j]!=-1)
    				f[i][j+1]=f[f[i][j]][j];
    		for(int i=1,s,e;i<=m;++i){
    			scanf("%d %d", &s, &e);
    			int l=0, r=nn-1;
    			while(l<r){
    				int m=l+r>>1;
    				if(seg[m].s<s)
    					l=m+1;
    				else
    					r=m;
    			}
    			if(seg[l].e>e||seg[l].s<s)puts("0");
    			else{
    				int ans=1;
    				for(int j=29;j>=0;--j){
    					if(f[r][j]!=-1&&seg[f[r][j]].e<=e){
    						r=f[r][j];
    						ans+=(1<<j);
    					}
    				}
    				printf("%d
    ", ans);
    			}
    		}
    	}
    	return 0;
    }
    

    1045ms

    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    #define N 100005
    using namespace std;
    struct Seg {
        int s, e;
        bool operator < (const Seg &b) const {
            return e < b.e || e == b.e && s > b.s;
        }
    } seg[N];
    int n, m;
    int main() {
        while(~scanf("%d %d", &n, &m)) {
            for(int i = 0; i < n; ++i)
                scanf("%d %d", &seg[i].s, &seg[i].e);
            sort(seg, seg + n);
            int nn = 0;
            for(int i = 1; i < n; ++i)
                if(seg[nn].s < seg[i].s)
                    seg[++nn] = seg[i];
            ++nn;
            for(int i = 1, s, e; i <= m; ++i) {
                scanf("%d %d", &s, &e);
                int l = 0, r = nn - 1;
                while(l < r) {
                    int m = l + r >> 1;
                    if(seg[m].s < s)
                        l = m + 1;
                    else
                        r = m;
                }
                if(seg[l].e > e || seg[l].s < s)puts("0");
                else {
                    int ans = 1;
                    for(int i = l, j = l + 1; j < nn && seg[j].e <= e; ++j) {
                        if(seg[i].e <= seg[j].s) {
                            i = j;
                            ++ans;
                        }
                    }
                    printf("%d
    ", ans);
                }
            }
        }
        return 0;
    }
    
  • 相关阅读:
    正则表达式实例
    正则表达式理解
    Git初体验
    浏览器加载解析HTML、JS、CSS的过程
    iframe
    纯前端,html页面间传值方式:
    Visual Code 之使用
    seajs使用记
    VBA中Dictionary对象使用(Key,Value)
    存储过程和存储函数和触发器示例
  • 原文地址:https://www.cnblogs.com/flipped/p/HDU4343.html
Copyright © 2020-2023  润新知