题意:给定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\n",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\n",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\n",ans[i]); 144 } 145 return 0; 146 }
时间: 2024-12-25 11:47:18