[LOJ 6029] 「雅礼集训 2017 Day1」市场

题意

给定一个长度为 \(n\) 的数列(从 \(0\) 开始标号), 要求执行 \(q\) 次操作, 每次操作为如下四种操作之一:

  • 1 l r c 给 \([l,r]\) 区间内的值全部加上 \(c\).
  • 2 l r d 给 \([l,r]\) 区间内的值全部除以 \(d\), 向下取整.
  • 3 l r 求 \([l,r]\) 区间内的最小值.
  • 4 l r 求 \([l,r]\) 区间内的值之和.

\(n,q\le 1\times 10^5, |c|\le1\times 10^4,d\in[2,1\times 10^9]\), 时限 \(2\texttt{s}\).

题解

玄学线段树.

首先看到题目容易想到一个数最多除 $\log $ 次就会变成 \(0/1\). 但是区间加法操作让这个势能分析假掉了. (单点加法是滋磁的)

注意到在除法操作中每除一次就会导致区间内的数的浮动量 (即 \(\max - \min\)) 至少减半. 而加法操作虽然是区间操作, 但是对浮动量造成的变化只有常数个位置(两端). 而相近的一坨数整体除法可以看作是进行了一次区间加法操作.

又因为当 \(x\) 递增的时候 \(\left \lfloor \frac x d \right \rfloor\) 单调不降, 于是只要 \(\left \lfloor \frac \max d \right \rfloor - \max=\left \lfloor \frac \min d \right \rfloor -\min\), 那么整个区间产生的差值都是一样的, 都可以用一次区间加法操作代替. 而一次区间加法是 \(O(\log n)\) 的, 于是总复杂度是 \(O(q\log n\log V)\).

参考代码

#include <bits/stdc++.h>

const int MAXN=1e5+10;
typedef long long intEx; struct Node{
int l;
int r;
int max;
int min;
int add;
intEx sum;
Node* lch;
Node* rch;
Node(int,int);
void Add(int);
void PushDown();
void Maintain();
void Add(int,int,int);
void Div(int,int,int);
int QueryMin(int,int);
intEx QuerySum(int,int);
}; int n;
int q;
int a[MAXN]; int ReadInt();
inline int FDiv(int,int); int main(){
n=ReadInt(),q=ReadInt();
for(int i=0;i<n;i++)
a[i]=ReadInt();
Node* N=new Node(0,n-1);
for(int i=0;i<q;i++){
int t=ReadInt(),l=ReadInt(),r=ReadInt();
if(t==1){
int d=ReadInt();
N->Add(l,r,d);
}
else if(t==2){
int d=ReadInt();
N->Div(l,r,d);
}
else if(t==3)
printf("%d\n",N->QueryMin(l,r));
else if(t==4)
printf("%lld\n",N->QuerySum(l,r));
}
return 0;
} intEx Node::QuerySum(int l,int r){
if(l<=this->l&&this->r<=r)
return this->sum;
else{
this->PushDown();
if(r<=this->lch->r)
return this->lch->QuerySum(l,r);
if(this->rch->l<=l)
return this->rch->QuerySum(l,r);
return this->lch->QuerySum(l,r)+this->rch->QuerySum(l,r);
}
} int Node::QueryMin(int l,int r){
if(l<=this->l&&this->r<=r)
return this->min;
else{
this->PushDown();
if(r<=this->lch->r)
return this->lch->QueryMin(l,r);
if(this->rch->l<=l)
return this->rch->QueryMin(l,r);
return std::min(this->lch->QueryMin(l,r),this->rch->QueryMin(l,r));
}
} void Node::Add(int l,int r,int d){
if(l<=this->l&&this->r<=r)
this->Add(d);
else{
this->PushDown();
if(l<=this->lch->r)
this->lch->Add(l,r,d);
if(this->rch->l<=r)
this->rch->Add(l,r,d);
this->Maintain();
}
} void Node::Div(int l,int r,int d){
if(l<=this->l&&this->r<=r){
if(this->max-FDiv(this->max,d)==this->min-FDiv(this->min,d))
this->Add(FDiv(this->max,d)-this->max);
else{
this->PushDown();
this->lch->Div(l,r,d);
this->rch->Div(l,r,d);
this->Maintain();
}
}
else{
this->PushDown();
if(l<=this->lch->r)
this->lch->Div(l,r,d);
if(this->rch->l<=r)
this->rch->Div(l,r,d);
this->Maintain();
}
} inline void Node::Add(int d){
this->max+=d;
this->min+=d;
this->add+=d;
this->sum+=1ll*(this->r-this->l+1)*d;
} inline void Node::Maintain(){
this->sum=this->lch->sum+this->rch->sum;
this->max=std::max(this->lch->max,this->rch->max);
this->min=std::min(this->lch->min,this->rch->min);
} inline void Node::PushDown(){
if(this->add!=0){
this->lch->Add(this->add);
this->rch->Add(this->add);
this->add=0;
}
} Node::Node(int l,int r):l(l),r(r),max(a[l]),min(a[r]),add(0),sum(a[l]),lch(NULL),rch(NULL){
if(l!=r){
int mid=(l+r)>>1;
this->lch=new Node(l,mid);
this->rch=new Node(mid+1,r);
this->Maintain();
}
} inline int ReadInt(){
int x=0,sgn=1;
register char ch=getchar();
while(!isdigit(ch)){
if(ch=='-')
sgn=-sgn;
ch=getchar();
}
while(isdigit(ch)){
x=x*10+ch-'0';
ch=getchar();
}
return x*sgn;
} inline int FDiv(int x,int d){
if(x>=0)
return x/d;
else
return (x-d+1)/d;
}

[LOJ 6029]「雅礼集训 2017 Day1」市场的更多相关文章

  1. loj#6029. 「雅礼集训 2017 Day1」市场(线段树)

    题意 链接 Sol 势能分析. 除法是不能打标记的,所以只能暴力递归.这里我们加一个剪枝:如果区间内最大最小值的改变量都相同的话,就变成区间减. 这样复杂度是\((n + mlogn) logV\)的 ...

  2. LOJ #6029. 「雅礼集训 2017 Day1」市场 线段树维护区间除法

    题目描述 从前有一个贸易市场,在一位执政官到来之前都是非常繁荣的,自从他来了之后,发布了一系列奇怪的政令,导致贸易市场的衰落. 有 \(n\) 个商贩,从\(0 \sim n - 1\) 编号,每个商 ...

  3. #6029. 「雅礼集训 2017 Day1」市场 [线段树]

    考虑到每次除法,然后加法,差距会变小,于是维护加法lazytag即可 #include <cstdio> #include <cmath> #define int long l ...

  4. [LOJ 6031]「雅礼集训 2017 Day1」字符串

    [LOJ 6031] 「雅礼集训 2017 Day1」字符串 题意 给定一个长度为 \(n\) 的字符串 \(s\), \(m\) 对 \((l_i,r_i)\), 回答 \(q\) 个询问. 每个询 ...

  5. [LOJ 6030]「雅礼集训 2017 Day1」矩阵

    [LOJ 6030] 「雅礼集训 2017 Day1」矩阵 题意 给定一个 \(n\times n\) 的 01 矩阵, 每次操作可以将一行转置后赋值给某一列, 问最少几次操作能让矩阵全为 1. 无解 ...

  6. loj 6031「雅礼集训 2017 Day1」字符串

    loj 注意到每次询问串长度都是给定的,并且询问串长\(k*\)询问次数\(q<10^5\),所以这里面一个东西大的时候另一个东西就小,那么考虑对较小的下功夫 如果\(k\le \sqrt{n} ...

  7. loj#6031. 「雅礼集训 2017 Day1」字符串(SAM 广义SAM 数据分治)

    题意 链接 Sol \(10^5\)次询问每次询问\(10^5\)个区间..这种题第一感觉就是根号/数据分治的模型. \(K\)是个定值这个很关键. 考虑\(K\)比较小的情况,可以直接暴力建SAM, ...

  8. loj#6030. 「雅礼集训 2017 Day1」矩阵(贪心 构造)

    题意 链接 Sol 自己都不知道自己怎么做出来的系列 不难观察出几个性质: 最优策略一定是先把某一行弄黑,然后再用这一行去覆盖不是全黑的列 无解当且仅当无黑色.否则第一个黑色所在的行\(i\)可以先把 ...

  9. loj6029 「雅礼集训 2017 Day1」市场

    传送门:https://loj.ac/problem/6029 [题解] 考虑如果有一些近似连续的段 比如 2 2 2 3 3 3,考虑在除3意义下,变成0 0 0 1 1 1,相当于整体-2 又:区 ...

随机推荐

  1. 导入maven项目遇到中文乱码

    windows->preferences->content types->word Document 并输入utf-8->update; 右键选中的项目,选择propertie ...

  2. Qt编写自定义控件12-进度仪表盘

    前言 进度仪表盘主要应用场景是标识一个任务进度完成的状况等,可以自由的设置范围值和当前值,为了美观还提供了四种指示器(圆形指示器/指针指示器/圆角指针指示器/三角形指示器),各种颜色都可以设置,其中的 ...

  3. 【angular5项目积累总结】avatar组件

    View Code import { Component, HostListener, ElementRef } from '@angular/core'; import { Adal4Service ...

  4. Winform下判断文件和文件夹是否存在

    //选择文件夹 FolderBrowserDialog dia = new FolderBrowserDialog(); if (dia.ShowDialog() == System.Windows. ...

  5. C# Windows程序窗口置前台的几种方法

    这个是从别的地方看来的,放我这里 第一种:SetForegroundWindow,这个方法时灵时不灵.有人说,在自己的程序里把自己的窗口之前一般就不灵,而置前其它程序的窗口就灵.我觉得这是有原因的:当 ...

  6. 数据结构与算法--最小生成树之Prim算法

    数据结构与算法--最小生成树之Prim算法 加权图是一种为每条边关联一个权值或称为成本的图模型.所谓生成树,是某图的一棵含有全部n个顶点的无环连通子图,它有n - 1条边.最小生成树(MST)是加权图 ...

  7. Java虚拟机 - 语法糖

    [深入Java虚拟机]之六:Java语法糖 语法糖(Syntactic Sugar),也称糖衣语法,是由英国计算机学家Peter.J.Landin发明的一个术语,指在计算机语言中添加的某种语法,这种语 ...

  8. 一道很好的mysql面试练习题,having综合应用

    写一条SQL语句,求出2门以及2门以上不及格的科目平均分 >要出现2门以及2门以上的学科不及格 >计算该考生所有学科的平均分,不单是,不及格的那几门 #创建表: create table ...

  9. git 本地安装

    一.基本安装 1.下载Git   官方地址为:https://git-scm.com/download/win 2.下载完之后,双击安装,全部选择默认. 3.选择安装目录 4.选择组件 5.开始菜单目 ...

  10. python乐观锁、悲观锁

    二.乐观锁总是认为不会产生并发问题,每次去取数据的时候总认为不会有其他线程对数据进行修改,因此不会上锁,但是在更新时会判断其他线程在这之前有没有对数据进行修改 三.悲观锁总是假设最坏的情况,每次取数据 ...