CF 46D D. Parking Lot 线段树成段更新

本文探讨了在解决复杂问题时如何通过优化代码结构和利用高效的数据结构来提高程序性能,详细介绍了几种常见数据结构的应用场景及优化策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目:http://www.codeforces.com/problemset/problem/46/D

题意:就是模拟车的停靠,然后要求车前和车后要有空间。。。

这题和我前几天做的题目差不多。。。所以就直接顺手写了。。。。。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=101002;
int lmax[maxn<<2],rmax[maxn<<2],mmax[maxn<<2],op,col[maxn<<2],n,m,f,b,st[102],ed[102];
#define lson rt<<1,l,mid
#define rson rt<<1|1,mid+1,r
void pushup(int rt,int l,int r)
{
    int mid=(l+r)>>1;
    lmax[rt]=lmax[rt<<1];
    rmax[rt]=rmax[rt<<1|1];
    mmax[rt]=max(mmax[rt<<1],mmax[rt<<1|1]);
    mmax[rt]=max(mmax[rt],rmax[rt<<1]+lmax[rt<<1|1]);
    if(lmax[rt<<1]==mid-l+1) lmax[rt]+=lmax[rt<<1|1];
    if(rmax[rt<<1|1]==r-mid) rmax[rt]+=rmax[rt<<1];
}
void pushdown(int rt,int l,int r)
{
    if(col[rt]!=-1)
    {
        int mid=(l+r)>>1;
        if(col[rt]==1)///已被占用
        {
            lmax[rt<<1]=rmax[rt<<1]=lmax[rt<<1|1]=rmax[rt<<1|1]=mmax[rt<<1]=mmax[rt<<1|1]=0;
        }
        else
        {
            lmax[rt<<1]=rmax[rt<<1]=mmax[rt<<1]=mid-l+1;
            lmax[rt<<1|1]=rmax[rt<<1|1]=mmax[rt<<1|1]=r-mid;
        }
        col[rt]=-1;
    }
}
void build(int rt,int l,int r)
{
    lmax[rt]=rmax[rt]=mmax[rt]=r-l+1;
    col[rt]=-1;
    if(l==r)return;
    int mid=(l+r)>>1;
    build(lson);
    build(rson);
    pushup(rt,l,r);
}
void updata(int rt,int l,int r,int L,int R,int val)
{
    if(L<=l&&r<=R)
    {
        col[rt]=val;
        lmax[rt]=rmax[rt]=mmax[rt]=(r-l+1)*(val^1);
        return ;
    }
    pushdown(rt,l,r);
    int mid=(l+r)>>1;
    if(mid>=L)updata(lson,L,R,val);
    if(mid<R)updata(rson,L,R,val);
    pushup(rt,l,r);
}
int query(int rt,int l,int r,int len)
{
    if(mmax[rt]<len)return -1;
    if(lmax[rt]>=len)return l;
    pushdown(rt,l,r);
    int mid=(l+r)>>1;
    if(mmax[rt<<1]>=len)return query(lson,len);
    if(rmax[rt<<1]+lmax[rt<<1|1]>=len)return mid-rmax[rt<<1]+1;
    return query(rson,len);
}
int main()
{
    int i,j,idx;
    while(scanf("%d%d%d",&n,&b,&f)!=EOF)
    {
        n=n+b+f-1;
        build(1,0,n);
        scanf("%d",&m);
        for(i=1; i<=m; i++)
        {
            scanf("%d%d",&op,&idx);
            if(op==1)
            {
                int len=idx+b+f;///车占的空间长度
                int k=query(1,0,n,len);
                printf("%d\n",k);
                if(k!=-1)
                {
                    st[i]=k+b;///车头的位置
                    ed[i]=k+b+idx-1;///车尾的位置
                    updata(1,0,n,st[i],ed[i],1);
                }
            }
            else
            {
                updata(1,0,n,st[idx],ed[idx],0);
            }
        }
    }
    return 0;
}
/*
30 1 2
6
1 5
1 4
1 5
2 2
1 5
1 4
30 1 1
6
1 5
1 4
1 5
2 2
1 5
1 4
*/


 

题目描述 给定一个长度为 $n$ 的序列 $a_1, a_2, \cdots, a_n$。 定义一个数 $k$ 的权值为 $w_k$,其中 $w_k$ 为 $k$ 的因数中 1 的个数。 定义一个区间 $[l,r]$ 的权值为 $\gcd\{a_l,a_{l+1},\cdots,a_r\}$ 的权值。 现在有 $m$ 次操作,每次操作为将区间 $[l,r]$ 内的数加上 $x$(即 $a_l\gets a_l+x,a_{l+1}\gets a_{l+1}+x,\cdots,a_r\gets a_r+x$)。 对于每次操作,求出操作后 $[1,n]$ 中有多少个区间的权值为素数。 输入格式 第一行包含两个整数 $n,m$。 第二行包含 $n$ 个整数 $a_1,a_2,\cdots,a_n$。 接下来 $m$ 行,每行包含三个整数 $l,r,x$,表示对区间 $[l,r]$ 内的数加上 $x$。 输出格式 对于每次操作,输出操作后 $[1,n]$ 中有多少个区间的权值为素数。 数据范围 $1\le n\le 10^5$, $1\le m\le 10^5$, $1\le a_i,x\le 10^6$ 输入样例: 5 3 1 2 3 4 5 1 5 1 2 3 2 1 3 1 输出样例: 3 4 3 解题思路 注意到一个数的因数中 1 的个数只与其质因数分解后的指数有关,可以预处理出每个质数的指数数组,即 primes[i] 表示第 $i$ 个质数的指数。 对于每个区间 $[l,r]$,求出其权值的质因数分解,即对于每个质数 $p$,求出区间 $[l,r]$ 内 $p$ 的最小指数 $k$,则该区间的权值为 $\prod_{i=1}^np^{k_i}$ 的权值。 然后我们可以把区间加操作看做将区间内所有数乘上 $x+1$,那么区间内每个质数的指数也都加上了 $1$,因此只需要实现一个支持区间乘的数据结构即可。 考虑使用线段树维护区间乘积,对于每个节点,我们可以维护其子节点的质因数分解的指数数组,然后合并子节点时,将指数数组相应位置相加即可。 对于查询区间权值是否为素数,我们可以使用线性筛判定。 时间复杂度 每次操作的时间复杂度为 $O(\log n + k\log n)$,其中 $k$ 为质因数的个数,因此总时间复杂度为 $O(m\log n + kn\log n)$。 C++ 代码 ``` #include <iostream> #include <cstring> #include <algorithm> #include <cmath> using namespace std; const int N = 100010, M = 1000000; int n, m; int w[M + 10]; // w表示每个数的权值 int primes[N], cnt; // primes表示前cnt个质数 int id[M + 10]; // id[i]表示i这个数在primes数组中的位置 int st[N << 2][20]; // st表示线段树节点中每个质数的指数 bool is_prime[M + 10]; // is_prime[i]表示i是否为质数 int res; // res表示答案 void get_primes(int n) { for (int i = 2; i <= n; i ++ ) { if (!is_prime[i]) primes[cnt ++ ] = i; for (int j = 0; primes[j] <= n / i; j ++ ) { is_prime[primes[j] * i] = true; if (i % primes[j] == 0) break; } } } void init() { for (int i = 2; i <= M; i ++ ) if (!is_prime[i]) { int t = i, cnt = 0; while (t <= M) w[t] ++, t *= i, cnt ++ ; } get_primes(N - 1); for (int i = 1; i <= cnt; i ++ ) id[primes[i]] = i; } void pushup(int u) { for (int i = 1; i <= cnt; i ++ ) st[u][i] = st[u << 1][i] + st[u << 1 | 1][i]; } void build(int u, int l, int r) { if (l == r) { st[u][id[w[l]]] = 1; return; } int mid = l + r >> 1; build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r); pushup(u); } void modify(int u, int l, int r, int ql, int qr, int c) { if (ql <= l && r <= qr) { for (int i = 1; i <= cnt; i ++ ) st[u][i] += c * st[u][i]; return; } int mid = l + r >> 1; if (ql <= mid) modify(u << 1, l, mid, ql, qr, c); if (qr > mid) modify(u << 1 | 1, mid + 1, r, ql, qr, c); pushup(u); } void query(int u, int l, int r, int k) { if (l == r) { bool is_prime = true; for (int i = 2; i <= sqrt(w[l]); i ++ ) if (w[l] % i == 0) { is_prime = false; break; } if (w[l] <= 1) is_prime = false; if (is_prime) res += st[u][k]; return; } int mid = l + r >> 1; query(u << 1, l, mid, k), query(u << 1 | 1, mid + 1, r, k); } int main() { init(); scanf("%d%d", &n, &m); build(1, 1, n); while (m -- ) { int l, r, x; scanf("%d%d%d", &l, &r, &x); modify(1, 1, n, l, r, x); res = 0; query(1, 1, n, x + 1); printf("%d\n", res); } return 0; } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值