• 【hdu5381】维护区间内所有子区间的gcd之和-线段树


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

    题解:

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

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

      1 #include<cstdio>
      2 #include<cstdlib>
      3 #include<cstring>
      4 #include<iostream>
      5 #include<algorithm>
      6 using namespace std;
      7 
      8 typedef long long LL;
      9 const LL N=2*100010;
     10 LL n,m,tl,al,last;
     11 LL val[N],ans[N];
     12 struct node{
     13     LL l,r,last,next;
     14     LL d;
     15 }a[N];
     16 struct trnode{
     17     LL l,r,lc,rc;
     18     LL d,lazy;
     19 }t[2*N];
     20 struct nd{
     21     LL l,r,id;
     22 }q[N];
     23 
     24 bool cmp_r(nd x,nd y){return x.r<y.r;}
     25 
     26 LL gcd(LL x,LL y)
     27 {
     28     if(y==0) return x;
     29     return gcd(y,x%y);
     30 }
     31 
     32 LL bt(LL l,LL r)
     33 {
     34     LL x=++tl;
     35     t[x].l=l;t[x].r=r;
     36     t[x].lc=t[x].rc=0;
     37     t[x].d=0;t[x].lazy=0;
     38     if(l<r)
     39     {
     40         LL mid=(l+r)/2;
     41         t[x].lc=bt(l,mid);
     42         t[x].rc=bt(mid+1,r);
     43     }
     44     return x;
     45 }
     46 
     47 void pd(LL x)
     48 {
     49     if(t[x].lazy==0) return ;
     50     LL lc=t[x].lc,rc=t[x].rc;
     51     LL d=t[x].lazy;
     52     t[x].d+=(t[x].r-t[x].l+1)*d;
     53     t[x].lazy=0;
     54     if(lc) t[lc].lazy+=d;
     55     if(rc) t[rc].lazy+=d;
     56 }
     57 
     58 void change(LL x,LL l,LL r,LL d)
     59 {
     60     pd(x);
     61     if(t[x].l==l && t[x].r==r) {t[x].lazy+=d;pd(x);return ;}
     62     LL lc=t[x].lc,rc=t[x].rc,mid=(t[x].l+t[x].r)/2;
     63     if(r<=mid) change(lc,l,r,d);
     64     else if(l>mid) change(rc,l,r,d);
     65     else
     66     {
     67         change(lc,l,mid,d);
     68         change(rc,mid+1,r,d);
     69     }
     70     if(lc) pd(lc);
     71     if(rc) pd(rc);
     72     t[x].d=t[lc].d+t[rc].d;
     73 }
     74 
     75 LL query(LL x,LL l,LL r)
     76 {
     77     pd(x);
     78     if(t[x].l==l && t[x].r==r) return t[x].d;
     79     LL lc=t[x].lc,rc=t[x].rc,mid=(t[x].l+t[x].r)/2;
     80     if(r<=mid) return query(lc,l,r);
     81     if(l>mid) return query(rc,l,r);
     82     return query(lc,l,mid)+query(rc,mid+1,r);
     83 }
     84 
     85 int main()
     86 {
     87     freopen("a.in","r",stdin);
     88     freopen("a.out","w",stdout);
     89     LL T;
     90     scanf("%lld",&T);
     91     while(T--)
     92     {
     93         scanf("%lld",&n);
     94         for(LL i=1;i<=n;i++)
     95         {
     96             scanf("%lld",&val[i]);
     97         }
     98         scanf("%lld",&m);
     99         for(LL i=1;i<=m;i++)
    100         {
    101             scanf("%lld%lld",&q[i].l,&q[i].r);
    102             if(q[i].l>q[i].r) swap(q[i].l,q[i].r);
    103             q[i].id=i;
    104         }
    105         sort(q+1,q+1+m,cmp_r);
    106         tl=0;bt(1,n);
    107         al=0;last=0;LL p,k=1;
    108         for(LL i=1;i<=n;i++) a[i].last=a[i].next=0;//debug 清零 不然下面找a[j].next的时候沿用了上一次的会导致死循环
    109         for(LL i=1;i<=n;i++)
    110         {
    111             a[++al].l=i;a[al].r=i;a[al].d=val[i];
    112             a[al].last=last;
    113             if(last) a[last].next=al;
    114             last=al;
    115             
    116             for(LL j=last;j;j=a[j].last) 
    117             {
    118                 a[j].d=gcd(a[j].d,val[i]);
    119             }
    120             for(LL j=last;j;j=a[j].last)
    121             {
    122                 p=a[j].last;
    123                 if(p && a[p].d==a[j].d)
    124                 {
    125                     a[p].r=a[j].r;
    126                     a[p].next=a[j].next;
    127                     if(a[j].next) a[a[j].next].last=p;
    128                     else last=p;
    129                 }
    130             }
    131             // printf("i = %lld
    ",i);
    132             for(LL j=last;j;j=a[j].last)
    133             {
    134                 change(1,a[j].l,a[j].r,a[j].d);
    135                 // printf("l = %lld  r = %lld  d = %lld
    ",a[j].l,a[j].r,a[j].d);
    136             }
    137             while(k<=m && q[k].r==i)
    138             {
    139                 ans[q[k].id]=query(1,q[k].l,q[k].r);
    140                 k++;
    141             }
    142         }
    143         for(LL i=1;i<=m;i++) printf("%lld
    ",ans[i]);
    144     }
    145     return 0;
    146 }
  • 相关阅读:
    JS高程3:面向对象的程序设计——理解对象
    JS高程3:函数表达式
    JS高程3:事件
    JS高程3:表单脚本
    InnoDB:表
    InnoDB:文件
    Springboot项目配置druid数据库连接池,并监控统计功能
    linux上修改mysql登陆密码
    上传本地文件到GitHub上
    logback.xml的使用,将日志异步保存到数据库中
  • 原文地址:https://www.cnblogs.com/KonjakJuruo/p/6056156.html
Copyright © 2020-2023  润新知