CSP模拟10

Because love you everyday.

A. Because

签到题,但是要特判,挂 \(\text{40 pts}\)

B. Love

双指针。

思路感觉很清奇。

我们用结构体存每一个数,保存它的值和它所属的集合,然后按照值把所有集合的数放到一起去。

然后用双指针维护。

#include <algorithm>
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <climits>

using namespace std;

const int N = 1005000;

int n,k,c[N];
int cnt;

struct Node{
    int val,id;
}a[N << 2];

bool cmp(Node x,Node y) {
    return x.val < y.val;
}

int vis[N],tot;

int main() {
    ios::sync_with_stdio(false);
    cin >> k;
    for(int i = 1;i <= k; i++) {
        cin >> c[i];
        for(int j = 1;j <= c[i]; j++) {
            cnt ++;
            cin >> a[cnt].val;
            a[cnt].id = i;
        }
    }
    n = cnt;

    sort(a + 1,a + n + 1,cmp);

    int l,r,ans = INT_MAX;
    for(l = 1,r = 1;r <= n; r ++) {
        if(vis[a[r].id])
            vis[a[r].id] ++;
        else {
            vis[a[r].id] ++;
            tot ++;
        }

        while(tot == k) {
            if(tot == k)
                ans = min(ans,a[r].val - a[l].val);

            if(vis[a[l].id] == 1)
                tot --;
            vis[a[l].id] --;
            l ++;
        }
    }
    cout << ans;
    return 0;
}

C. You

咕了。

D. Everyday

我们令一个区间的宝石能组成的价值范围为一个集合。

我们先讨论宝石如何组成不同的价值。

先考虑每个宝石必须被选的情况,那么对于两个宝石,他们的价值区间是 \(\left[l_1,r_1 \right]\)\(\left[l_2,r_2 \right]\),他们两个能表示的区间即为二者左右区间各自相加,即 \(\left[l_1 + l_2,r_1 + r_2 \right]\)

然后再考虑不选某个宝石的情况,我们给每个宝石能够组成的价值范围加上一个 \(\left[ 0,0 \right]\),这样表示不选该宝石的情况,容易发现,这样仍然符合原本的运算方式,左右边界相加。

所以我们可以用线段树维护,每个结点表示的是对应区间的宝石能够组成的价值区间的集合。

Pushup 时直接进行 \(\mathcal{O}(n^2)\) 的暴力合并,注意处理一下有没有重叠的区间,把他们合并。

这样我们就可以利用线段树进行区间查询了。

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>

using namespace std;

#define N 100500
#define int long long
typedef pair<int,int> Pair;
typedef vector<Pair> Vector;

int n,m;

Pair a[N];

struct Segment{
    int l,r;
    Vector Set;
}t[N << 2];

#define lid id << 1
#define rid id << 1 | 1

class Segment_Tree{
private:
    Vector Merge(Vector l,Vector r) {
    	if(l.empty())
			return r;
		
		if(r.empty())
			return l; 
    	
        Vector res;
        for(int i = 0;i < l.size(); i++)
            for(int j = 0;j < r.size(); j++)
                res.push_back(make_pair(l[i].first + r[j].first,l[i].second + r[j].second));

        stable_sort(res.begin(),res.end());

        int len = res.size();
        for(auto iter = res.begin();iter != res.end();) {
            auto iter2 = next(iter);

            if(iter2 == res.end())
                break;

            if (iter2->first <= iter->second) {
                iter->second = max(iter->second, iter2->second);
                res.erase(iter2);
            }
            else {
                ++iter;
            }
            
        }

        return res;
    }
    void Pushup(int id) {
        t[id].Set = Merge(t[lid].Set,t[rid].Set);
        return ;
    }
public:
    void Build(int id,int l,int r) {
        t[id].l = l;
        t[id].r = r;

        if(l == r) {
            t[id].Set.push_back(make_pair(0,0));
            t[id].Set.push_back(a[l]);
            return ;
        }

        int mid = (l + r) >> 1;
        Build(lid,l,mid);
        Build(rid,mid + 1,r);

        Pushup(id);
        return ;
    }

    void Change(int id,int pos,Vector val) {
        if(t[id].l == t[id].r) {
            t[id].Set = val;
            return ;
        }

        int mid = (t[id].l + t[id].r) >> 1;
        if(pos <= mid)
            Change(lid,pos,val);
        else
            Change(rid,pos,val);
        
        Pushup(id);
        return ;
    }
    
    Vector Query(int id,int l,int r) {
        if(l <= t[id].l && t[id].r <= r)
            return t[id].Set;
        
        int mid = (t[id].l + t[id].r) >> 1;
        Vector tmp1,tmp2,ans;
        if(l <= mid)
            tmp1 = Query(lid,l,r);
        if(r > mid)
            tmp2 = Query(rid,l,r);

        ans = Merge(tmp1,tmp2);
        return ans;
    }
}tree;

#undef lid
#undef rid

signed main() {
    ios::sync_with_stdio(false);
    cin >> n >> m;
    for(int i = 1;i <= n; i++)
        cin >> a[i].first >> a[i].second;
    
    tree.Build(1,1,n);

    for(int i = 1,opt,k,l,r;i <= m; i++) {
        cin >> opt;
        if(opt == 1) {
            cin >> k >> l >> r;
            Vector tmp;
            tmp.push_back(make_pair(0,0));
            tmp.push_back(make_pair(l,r));
            tree.Change(1,k,tmp);
        }
        else {
            cin >> l >> r;
            Vector ans = tree.Query(1,l,r);
            int sum = 0;
            for(int i = 0;i < ans.size(); i++)
                sum += ans[i].second - ans[i].first + 1;
            cout << sum << "\n";
        }
    }
    return 0;
}
posted @ 2023-07-31 21:40  -白简-  阅读(10)  评论(0编辑  收藏  举报