zoukankan      html  css  js  c++  java
  • [CF369E] Valera and Queries

    Description

    给定 (n) 条线段 ([l_i,r_i]),有 (m) 个询问,每次给定若干个点,问多少线段能至少覆盖这些点中的一个。

    Solution

    补集转化,求多少线段一个点也不能覆盖。

    点将数轴分割成了一个线段集,即求有多少原始线段是包含在询问线段集中的一个线段中的。

    要询问一个线段包含的原始线段个数,考虑离线处理,用树状数组维护即可。

    具体地,按右端点排序后扫描,扫到一个原始线段就在树状数组的左端点位置加一,扫到一个询问线段就直接扫描部分的后缀和来统计答案(扫描顺序保证了右端点顺序,后缀和保证了左端点关系,故询问线段包含了原始线段)

    #include <bits/stdc++.h>
    using namespace std;
    
    #define int long long
    const int N = 2000005;
    
    int n,m,cnt,p[N];
    
    struct Segment
    {
        int l,r,ans;
        bool operator < (const Segment &obj)
        {
            return r < obj.r;
        }
    } seg[N];
    
    vector <Segment> segq;
    vector <int> qid[N];
    vector <int> segque[N],segsrc[N];
    
    int ar[N]; // index: 1 ~ N
    int lowbit(int t)
    {
        return t & (-t);
    }
    void add(int i, int v)
    {
        for (; i < N; ar[i] += v, i += lowbit(i));
    }
    int sum(int i)
    {
        if(i==0) return 0;
        int s = 0;
        for (; i > 0; s += ar[i], i -= lowbit(i));
        return s;
    }
    int query(int l,int r)
    {
        return sum(r)-sum(l-1);
    }
    signed main()
    {
        ios::sync_with_stdio(false);
    
        cin>>n>>m;
        int mx=1e6+1;
        for(int i=1; i<=n; i++)
        {
            int t1,t2;
            cin>>t1>>t2;
            seg[i]={t1,t2,0};
            segsrc[t2].push_back(i);
            mx=max(mx,max(t1,t2));
        }
        for(int i=1; i<=m; i++)
        {
            int cnt,t,last=0;
            cin>>cnt;
            while(cnt--)
            {
                cin>>t;
                if(t-last>1)
                {
                    qid[i].push_back(segq.size());
                    segque[t-1].push_back(segq.size());
                    segq.push_back({last+1,t-1});
                }
                last=t;
            }
            {
                int t=1e6+1;
                if(t-last>1)
                {
                    qid[i].push_back(segq.size());
                    segque[t-1].push_back(segq.size());
                    segq.push_back({last+1,t-1});
                }
                last=t;
            }
        }
        for(int i=1; i<=mx; i++)
        {
            for(int tid:segsrc[i])
            {
                Segment &tmp=seg[tid];
                add(tmp.l, 1);
                //cout<<"modify "<<tmp.l<<endl;
            }
            for(int tid:segque[i])
            {
                Segment &tmp=segq[tid];
                tmp.ans=query(tmp.l,tmp.r);
                //cout<<"tid="<<tid<<" ans="<<tmp.ans<<endl;
            }
        }
        for(int i=1;i<=m;i++)
        {
            int ans=n;
            for(int tid:qid[i])
            {
                //cout<<"calling tid="<<tid<<endl;
                Segment &tmp=segq[tid];
                ans-=tmp.ans;
            }
            cout<<ans<<endl;
        }
    }
    
    
  • 相关阅读:
    Java面试系列05(static、JVM内存模、final、abstract、interface)
    Java面试系列04(抽象、实例化、类、多态、对象、特殊对象、权限封装)
    第一个spring冲刺团队贡献分(80分满分)
    第二个Sprint冲刺第一天
    第一阶段的事后诸葛亮
    第一个Sprint冲刺成果
    第一个Sprint冲刺第十天
    第一个Sprint冲刺第九天
    第一个Sprint冲刺第八天
    第一个Sprint冲刺第七天
  • 原文地址:https://www.cnblogs.com/mollnn/p/13653559.html
Copyright © 2011-2022 走看看