HDU 4902 Nice boat 多校4 线段树
给定n个数
第一个操作和普通,区间覆盖性的,把l-r区间的所有值改成固定的val
第二个操作是重点,输入l r x 把l-r区间的所有大于x的数,变成gcd(a[i],x) a[i]即指满足条件的序列上的数值
最后才输出所有值
当时苦思这个地方如何优化,想着不可能单点去更新吧,但是区间gcd,不能保存下来,一来他是要>x才有效,本来聪哥想了一种先把各种x gcd一遍,最后在push下去,发现不行,就是因为他对>x才有效,你在区间就直接gcd了,那不是把不该gcd的也给搞了
还想过说先存起来所有的x,当然也有限制条件,就是说比较大的就不要了,因为gcd越搞越小,你后面来个大的x没意义,最后再push下去。。。我这样敲了一下,wa了,后来分析下,觉得这个根顺序还是有关系,我直接记录完,push下去没讲顺序 还是有问题的
后来居然claration有人讲他暴力过的,。。我也是醉了
当然不是真的完全暴力,还是要优化的,一个是大家都做了的,就是利用第一个操作,如果某区间都是一个值,那gcd直接在这个区间跟这个值弄一下,就可以了,不用再往下走了。
我还做了另一个优化,就是记录每个区间的最大值,要是当前x走到某个区间,发现比最大值还>=,那直接return即可,没有任何意义
后来终于是AC了,注意点细节,没什么太难的。不过后来讨论到为什么可以这样不超时,聪哥说有个lamp定理,可以证明每个int整数,最多不超过31次gcd就会变成1(感觉像二分一样,聪哥说这玩意衰变得很快),也就是说,我有了上述优化之后,实际每个数最多只要31次更新到底即可,n个数只要n*31次更新到底即可,其他的都会被优化掉,所以为什么不会超时。。。虽然我不明白这个31次是怎么来的,不过如果这个是成立的,那就完全可以解释这个算法了。,明天还去跟聪哥讨论一下这个lamp定理,看下到底是怎么证明出31次的
后来我AC之后又想优化一下,把原因的1操作的懒惰标记iss想变成状态型的,比如单个节点iss永远是1,表示他就是被自己覆盖了嘛,但是会WA,就是说,你状态型的,你上面的结构也要保持该状态,上面没处理好,很麻烦的。。所以不建议是这么混着来,懒惰标记就是懒惰标记,别混成状态标记了
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#define lson rt<<1,l,mid
#define rson rt<<1|1,mid+1,r
#define LL __int64
using namespace std;
const int N=100000+10;
int A[N];
int setv[N<<2],iss[N<<2],d[N<<2];
int gcd(int a,int b)
{
if (abs(a)<abs(b)) swap(a,b);
while (b)
{
int tmp=a;
a=b;
b=tmp%b;
}
return a;
}
int n;
void up(int rt)
{
d[rt]=max(d[rt<<1],d[rt<<1|1]);
if (setv[rt<<1]==setv[rt<<1|1] && iss[rt<<1] && iss[rt<<1|1]){
setv[rt]=setv[rt<<1];
iss[rt]=1;
}
}
void build(int rt,int l,int r)
{
iss[rt]=setv[rt]=0;
if (l>=r)
{
d[rt]=A[l];
return;
}
int mid=(l+r)>>1;
build(lson);
build(rson);
up(rt);
}
void pushdown(int rt,int l,int r)
{
if (l>=r) return;
if (iss[rt]){
d[rt]=setv[rt];
setv[rt<<1]=setv[rt<<1|1]=setv[rt];
d[rt<<1]=d[rt<<1|1]=setv[rt];
iss[rt<<1]=iss[rt<<1|1]=iss[rt];
iss[rt]=0; }
}
void fix(int L,int R,int val,int rt,int l,int r)
{
if (L<=l && r<=R)
{
iss[rt]=1;
setv[rt]=val;
d[rt]=val;
if (l==r) A[l]=val;
return;
}
pushdown(rt,l,r);
int mid=(l+r)>>1;
if (R<=mid) fix(L,R,val,lson);
else
if (L>mid) fix(L,R,val,rson);
else{
fix(L,R,val,lson);
fix(L,R,val,rson);
}
up(rt);
}
void fgcd(int L,int R,int val,int rt,int l,int r)
{
if (val>=d[rt]) return;
if (iss[rt] && L<=l && r<=R && l<r){
if (setv[rt]>val){
setv[rt]=gcd(setv[rt],val);
d[rt]=setv[rt];
}
return;
}
if (L==l && r==R && l==r)
{
if (iss[rt]){
A[l]=setv[rt];
d[rt]=A[l];
iss[rt]=0;
}
if (A[l]>val){
A[l]=gcd(A[l],val);
d[rt]=A[l];
}
return;
}
pushdown(rt,l,r);
int mid=(l+r)>>1;
if (R<=mid) fgcd(L,R,val,lson);
else
if (L>mid) fgcd(L,R,val,rson);
else
{
fgcd(L,mid,val,lson);
fgcd(mid+1,R,val,rson);
}
up(rt);
}
void merges(int rt,int l,int r)
{
if (l>=r)
{
if (iss[rt]){
A[l]=setv[rt];
d[l]=setv[rt];
iss[rt]=0;
}
return;
}
int mid=(l+r)>>1;
pushdown(rt,l,r);
merges(lson);
merges(rson);
}
int main()
{
int t,q,op;
scanf("%d",&t);
while (t--)
{
scanf("%d",&n);
for (int i=1;i<=n;i++){
scanf("%d",&A[i]);
}
build(1,1,n);
scanf("%d",&q);
while (q--)
{
int a,b,x;
scanf("%d",&op);
scanf("%d%d%d",&a,&b,&x);
if (op==1){
fix(a,b,x,1,1,n);
}
else{
fgcd(a,b,x,1,1,n);
}
}
merges(1,1,n);
for (int i=1;i<=n;i++){
printf("%d ",A[i]);
}
puts("");
}
return 0;
}
HDU 4902 Nice boat 多校4 线段树的更多相关文章
- HDU 4902 Nice boat 2014杭电多校训练赛第四场F题(线段树区间更新)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4902 解题报告:输入一个序列,然后有q次操作,操作有两种,第一种是把区间 (l,r) 变成x,第二种是 ...
- 2014多校第四场1006 || HDU 4902 Nice boat (线段树 区间更新)
题目链接 题意 : 给你n个初值,然后进行两种操作,第一种操作是将(L,R)这一区间上所有的数变成x,第二种操作是将(L,R)这一区间上所有大于x的数a[i]变成gcd(x,a[i]).输出最后n个数 ...
- HDU 4902 Nice boat (线段树)
Nice boat 题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=4902 Description There is an old country a ...
- 线段树 + 区间更新 ----- HDU 4902 : Nice boat
Nice boat Time Limit: 30000/15000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)Tot ...
- HDU 4902 Nice boat --线段树(区间更新)
题意:给一个数字序列,第一类操作是将[l,r]内的数全赋为x ,第二类操作是将[l,r]中大于x的数赋为该数与x的gcd,若干操作后输出整个序列. 解法: 本题线段树要维护的最重要的东西就是一个区间内 ...
- HDU 4960 Handling the past 2014 多校9 线段树
首先确定的基本思想是按时间离散化后来建线段树,对于每个操作插入到相应的时间点上 但是难就难在那个pop操作,我之前对pop操作的处理是找到离他最近的那个点删掉,但是这样对于后面的peak操作,如果时间 ...
- HDU 4893 2014多校三 线段树
给定一个初始都为0的序列,有三种操作,前两种比较正常,一个是对某个位置的数add k,另一个是query区间和.然后比较麻烦的是第三个操作,把某个区间里面的每个值改成离它最近的Fibonacci数,如 ...
- hdu acm 1166 敌兵布阵 (线段树)
敌兵布阵 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Submi ...
- HDU 4911 http://acm.hdu.edu.cn/showproblem.php?pid=4911(线段树求逆序对)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4911 解题报告: 给出一个长度为n的序列,然后给出一个k,要你求最多做k次相邻的数字交换后,逆序数最少 ...
随机推荐
- cookie注入
通常我们的开发人员在开发过程中会特别注意到防止恶意用户进行恶意的注入操作,因此会对传入的参数进行适当的过滤,但是很多时候,由于个人对安全技术了解的不同,有些开发人员只会对get,post这种方式提交的 ...
- 3676: [Apio2014]回文串 求回文串长度与出现次数的最大值
「BZOJ3676」[Apio2014] 回文串 Description 考虑一个只包含小写拉丁字母的字符串s.我们定义s的一个子串t的“出 现值”为t在s中的出现次数乘以t的长度.请你求出s的所 ...
- map的查询和修改方法
1:map查询的方法 package com.cn.util; import java.util.ArrayList; import java.util.HashMap; import java.ut ...
- JS 一键复制插件应用 和 原生实现
一.目前来说复制功能 clipboard.js基本可以兼容所有浏览器,可以任意复制文本,官方地址 https://clipboardjs.com/ 1.进入官方网站下载 然后引入 <script ...
- Linux CentOS7 VMware 文件和目录权限chmod、更改所有者和所属组chown、umask、隐藏权限lsattr/chattr
一.文件和目录权限chmod u User,即文件或目录的拥有者:g Group,即文件或目录的所属群组:o Other,除了文件或目录拥有者或所属群组之外,其他用户皆属于这个范围:a All,即全部 ...
- linux环境下安装solr
1.上传并解压solr文件 2.将solr解压缩包的dist/solr-4.10.3.war包部署到tomcat下.并改名为solr.war 3.解压war包(启动tomcat后会自动解压war包) ...
- mabatis--动态sql
1.mybatis核心,对sql语句进行灵活操作,通过表达式进行判断,对sql进行灵活拼接.组装: 2.使用if判断: <where> <if test="customer ...
- formatTime() 时间戳,返回数据是计算距离现在的时间
const formatTime=function(tiem) {//时间转换 const timestamp = Date.now(); return function (tiem) { ...
- 深入了解memcached
一.memcached如何支持高并发 Memcached使用多路复用 I/O模型(如epoll.select等).传统阻塞 I/O中,系统可能会因为某个用户连接还没做好 I/O准备而一直等待,直到这个 ...
- Python面试2未完待续
Python面试重点(基础篇) 注意:只有必答题部分计算分值,补充题不计算分值. 第一部分 必答题(每题2分) 简述列举了解的编程语言及语言间的区别? c语言是编译型语言,运行速度快,但翻译时间长py ...