题解 P1890 【gcd区间】

frankchenfu

2019-07-18 11:09:19

Solution

不得不说,~~这是一道线段树好题~~。 一看到这道题就想到了线段树——但是询问有$10^6$,怎么办? 哈!**zkw线段树,满足您的的各种~~卡常需求~~**! 实测zkw线段树在只有区间加、区间`max/min`的时候可以跑过$1.8\times 10^7$次操作(包括区间查询和单点修改); 而如果加上一些$\log$级别的询问,一般也可以过$5\times 10^6$的数据。 等一下……这道题不需要修改?那么预处理是$n=1000$的$n\log_2 n$,查询是$m\log_2 n\times \ln n$(`gcd`复杂度)。 因此这道题就可以zkw线段树快速解决。 顺带提醒一下楼下的几位dalao:~~你们都知道可以用线段树了还不写zkw,难道你准备被noip的老爷机卡常吗???~~ ```cpp #include<cstdio> #include<cstring> const int MAXN=4010; int d[MAXN]; int n,m,bit; int gcd(int x,int y){ return y==0?x:gcd(y,x%y); } void build(int n){ for(bit=1;bit<=n+1;bit<<=1); for(int i=bit+1;i<=bit+n;i++) scanf("%d",&d[i]); for(int i=bit-1;i;i--) d[i]=gcd(d[i<<1],d[i<<1|1]); } void update(int x,int y){ for(d[x+=bit]=y,x>>=1;x;x>>=1) d[x]=gcd(d[x<<1],d[x<<1|1]); } int query(int s,int t){ int ans=d[s+bit]; for(s+=bit-1,t+=bit+1;s^t^1;s>>=1,t>>=1){ if(~s&1) ans=gcd(ans,d[s^1]); if(t&1) ans=gcd(ans,d[t^1]); } return ans; } int main(){ scanf("%d%d",&n,&m); build(n); for(int i=1;i<=m;i++){ int l,r;scanf("%d%d",&l,&r); printf("%d\n",query(l,r)); } return 0; } ```