题意:给定n个数,m个询问,每次询问一个区间内所有连续子区间的gcd的和。n,m<=10^5

题解:

这题和之前比赛的一题很像。我们从小到大枚举r,固定右端点枚举左端点,维护的区间最多只有log段。为什么?以为长区间的gcd肯定是短区间gcd的约数,并且要是不同的话至少要/2,最多那就只有log数值这么多段。还有,相同gcd的区间一定是连续的若干个(想想gcd是怎么求的就知道了)。
线段树每个端点x维护的是以x为左端点,r从1到当前的r的gcd的和。链表维护log段数,然后每次加到线段树里更新。

tle了很久才找到错。清零啊!

 #include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std; typedef long long LL;
const LL N=*;
LL n,m,tl,al,last;
LL val[N],ans[N];
struct node{
LL l,r,last,next;
LL d;
}a[N];
struct trnode{
LL l,r,lc,rc;
LL d,lazy;
}t[*N];
struct nd{
LL l,r,id;
}q[N]; bool cmp_r(nd x,nd y){return x.r<y.r;} LL gcd(LL x,LL y)
{
if(y==) return x;
return gcd(y,x%y);
} LL bt(LL l,LL r)
{
LL x=++tl;
t[x].l=l;t[x].r=r;
t[x].lc=t[x].rc=;
t[x].d=;t[x].lazy=;
if(l<r)
{
LL mid=(l+r)/;
t[x].lc=bt(l,mid);
t[x].rc=bt(mid+,r);
}
return x;
} void pd(LL x)
{
if(t[x].lazy==) return ;
LL lc=t[x].lc,rc=t[x].rc;
LL d=t[x].lazy;
t[x].d+=(t[x].r-t[x].l+)*d;
t[x].lazy=;
if(lc) t[lc].lazy+=d;
if(rc) t[rc].lazy+=d;
} void change(LL x,LL l,LL r,LL d)
{
pd(x);
if(t[x].l==l && t[x].r==r) {t[x].lazy+=d;pd(x);return ;}
LL lc=t[x].lc,rc=t[x].rc,mid=(t[x].l+t[x].r)/;
if(r<=mid) change(lc,l,r,d);
else if(l>mid) change(rc,l,r,d);
else
{
change(lc,l,mid,d);
change(rc,mid+,r,d);
}
if(lc) pd(lc);
if(rc) pd(rc);
t[x].d=t[lc].d+t[rc].d;
} LL query(LL x,LL l,LL r)
{
pd(x);
if(t[x].l==l && t[x].r==r) return t[x].d;
LL lc=t[x].lc,rc=t[x].rc,mid=(t[x].l+t[x].r)/;
if(r<=mid) return query(lc,l,r);
if(l>mid) return query(rc,l,r);
return query(lc,l,mid)+query(rc,mid+,r);
} int main()
{
freopen("a.in","r",stdin);
freopen("a.out","w",stdout);
LL T;
scanf("%lld",&T);
while(T--)
{
scanf("%lld",&n);
for(LL i=;i<=n;i++)
{
scanf("%lld",&val[i]);
}
scanf("%lld",&m);
for(LL i=;i<=m;i++)
{
scanf("%lld%lld",&q[i].l,&q[i].r);
if(q[i].l>q[i].r) swap(q[i].l,q[i].r);
q[i].id=i;
}
sort(q+,q++m,cmp_r);
tl=;bt(,n);
al=;last=;LL p,k=;
for(LL i=;i<=n;i++) a[i].last=a[i].next=;//debug 清零 不然下面找a[j].next的时候沿用了上一次的会导致死循环
for(LL i=;i<=n;i++)
{
a[++al].l=i;a[al].r=i;a[al].d=val[i];
a[al].last=last;
if(last) a[last].next=al;
last=al; for(LL j=last;j;j=a[j].last)
{
a[j].d=gcd(a[j].d,val[i]);
}
for(LL j=last;j;j=a[j].last)
{
p=a[j].last;
if(p && a[p].d==a[j].d)
{
a[p].r=a[j].r;
a[p].next=a[j].next;
if(a[j].next) a[a[j].next].last=p;
else last=p;
}
}
// printf("i = %lld\n",i);
for(LL j=last;j;j=a[j].last)
{
change(,a[j].l,a[j].r,a[j].d);
// printf("l = %lld r = %lld d = %lld\n",a[j].l,a[j].r,a[j].d);
}
while(k<=m && q[k].r==i)
{
ans[q[k].id]=query(,q[k].l,q[k].r);
k++;
}
}
for(LL i=;i<=m;i++) printf("%lld\n",ans[i]);
}
return ;
}

【hdu5381】维护区间内所有子区间的gcd之和-线段树的更多相关文章

  1. [luoguP1440] 求m区间内的最小值(单调队列 || 线段树)

    传送门 这种水题没必要搞线段树了,单调队列就行啊. ——代码 #include <cstdio> ; , t = ; int a[MAXN], q[MAXN]; int main() { ...

  2. BZOJ 2752 [HAOI2012]高速公路(road):线段树【维护区间内子串和】

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2752 题意: 有一个初始全为0的,长度为n的序列a. 有两种操作: (1)C l r v: ...

  3. wannalfy 挑战赛7 E 珂朵莉与GCD (离线+线段树/树状数组)

    链接:https://www.nowcoder.com/acm/contest/56/E 时间限制:C/C++ 5秒,其他语言10秒 空间限制:C/C++ 716800K,其他语言1433600K 6 ...

  4. 【GDKOI2016Day1T1-魔卡少女】【拆位】线段树维护区间内所有连续子区间的异或和

    题意:给出N个数,M个操作.操作有修改和询问两种,每次修改将一个数改成另一个数,每次询问一个区间的所有连续子区间的异或和.n,m<=100000,ai<=1000 题解: 当年(其实也就是 ...

  5. 维护gcd的线段树 补发一波。。。

    基础线段树(辣鸡的不行) 发现自己线段树除了会维护加法和乘法就啥也不会了QWQ太菜了 瞎写了一个维护gcd的 首先,gcd(x,y)= gcd(x,y-x) 并且很容易推广到n个数,所以我们可以把原数 ...

  6. Master of GCD 【线段树区间更新 || 差分】

    Master of GCD 时间限制: 1 Sec  内存限制: 128 MB 提交: 670  解决: 112 [提交] [状态] [命题人:admin] 题目描述 Hakase has n num ...

  7. upc组队赛2 Master of GCD 【线段树区间更新 || 差分】

    Master of GCD 题目描述 Hakase has n numbers in a line. At fi rst, they are all equal to 1. Besides, Haka ...

  8. hdu 5381 The sum of gcd(线段树+gcd)

    题目链接:hdu 5381 The sum of gcd 将查询离线处理,依照r排序,然后从左向右处理每一个A[i],碰到查询时处理.用线段树维护.每一个节点表示从[l,i]中以l为起始的区间gcd总 ...

  9. 动态求区间K大值(权值线段树)

    我们知道我们可以通过主席树来维护静态区间第K大值.我们又知道主席树满足可加性,所以我们可以用树状数组来维护主席树,树状数组的每一个节点都可以开一颗主席树,然后一起做. 我们注意到树状数组的每一棵树都和 ...

随机推荐

  1. IOS开发基础知识--碎片30

    1:ios 相册操作 ALAssetsLibrary 知识点 a ALAssetsLibrary 实例为我们提供了获取相册(照片app)中的图片和视频的功能.在ios8 photos framewor ...

  2. java 实现 LINQ 的一些框架记录一下

    jOOQ: http://www.jooq.org JINQ: http://www.jinq.org JaQue: http://github.com/TrigerSoft/jaque JaQu:  ...

  3. Java unserialize serialized Object(AnnotationInvocationHandler、ysoserial) In readObject() LeadTo InvokerTransformer(Evil MethodName/Args)

    Java unserialize serialized Object(AnnotationInvocationHandler.ysoserial) In readObject() LeadTo Tra ...

  4. XIII Open Cup named after E.V. Pankratiev. GP of Azov Sea

    A. Freestyle 如果逆序对为$0$,那么先手必败. 因为每次只能翻转长度为$4k+2$和$4k+3$的区间,所以每次操作之后逆序对的奇偶性一定会发生改变. 因此如果逆序对个数为偶数,则先手必 ...

  5. linux下安装及配置和启动memcached

    一.下载文件: 下载memcached和libevent,放到/hom/zwl/目录下 # wget http://www.danga.com/memcached/dist/memcached-1.2 ...

  6. MyBatis知多少(16)MyBatis映射

    之前我们详细地讨论了MyBatis背后的设计理念以及iBATIS框架是如何产生的.也说明了MyBatis是一个混合型解决方案,它从处理关系数据库的其他不同方法那里借鉴了许多思想.那么MyBatis到底 ...

  7. [Math] Beating the binary search algorithm – interpolation search, galloping search

    From: http://blog.jobbole.com/73517/ 二分检索是查找有序数组最简单然而最有效的算法之一.现在的问题是,更复杂的算法能不能做的更好?我们先看一下其他方法. 有些情况下 ...

  8. 划分树 静态第k大

    划分树是保存了快速排序的过程的树,可以用来求静态第k小的数 如果,划分树可以看做是线段树,它的左孩子保存了mid-L+1 个 小于等于 a[mid] 的数字,  右孩子保存了 R-mid个大于等于a[ ...

  9. 安装Visual Studio 2010 - 初学者系列 - 学习者系列文章

    本文讲述如何安装Visual Studio 2010开发工具. 首先,通过下列地址获取Visual Studio 2010的副本 1.开始页面 2.欢迎页 3.这里选择 自定义 ,选择安装路径 4.这 ...

  10. 关于appium+模拟器+idea的细谈

    之前转载的虫师的appium移动端自动化的文章,前边appium环境的搭建,这里就不过多介绍了,不明白的小伙伴可以返回去看,后边有不会的步骤, 也都去看,总之,两篇文章结合看! 关于移动端自动化测试- ...