zoukankan      html  css  js  c++  java
  • hdu 5930 GCD 线段树上二分/ 强行合并维护信息

    from NOIP2016模拟题28

    题目大意

    n个点的序列,权值(<=10^6)
    q个操作
    1.单点修改
    2.求所有区间gcd中,不同数个数

    分析

    1.以一个点为端点,向左或向右的gcd种数都只有(log Maxval)种且收敛很快
    1.权值较小可以用桶统计一个gcd的出现次数

    做法1(正解)线段树上二分

    1. (n log n)递推预处理出以每个点为右端点的gcd
      顺便记录每种gcd出现的最左位置,用于统计数量,更新到桶里

    2. 可以用一颗线段树维护单点修改,区间gcd

    3. 考虑一次修改x(可以看成一次删除+一次插入)
      影响的只是包含x的区间
      根据分析1,我们在线段树上二分
      搞出x向左的(log)个gcd及出现的次数,和向右的....
      因为左边某个区间的所有数和右边某个区间的所有数两两gcd都相同
      (log^2)更新答案
      复杂度(log^2),再加个gcd 的log

    做法2 线段树强行维护

    每个点维护3个信息
    到左的log个gcd(tl)
    到右的log个gcd(tr)
    整个区间的gcd(all)
    pushup的时候更新tl,tr,O((log))
    左儿子tr和右儿子tl弄在一起gcd一下,O((log^2)),gcd还有一个(log)
    对于删除,点x到根上统计的信息都无效了,直接删掉
    在插入的时候重新统计
    复杂度(log^3),再加个gcd 的log

    比赛时强行意识流,求tl,tr的时候不顺带求出出现次数直接当成1
    然后现在想想好像并不会错→_→

    solution

    做法1

    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cctype>
    #include <cmath>
    #include <algorithm>
    using namespace std;
    const int M=50007;
    const int N=1000007;
    typedef long long LL;
    
    inline int rd(){
    	int x=0;bool f=1;char c=getchar();
    	for(;!isdigit(c);c=getchar()) if(c=='-') f=0;
    	for(;isdigit(c);c=getchar()) x=x*10+c-48;
    	return f?x:-x;
    }
    
    int n,m;
    int a[M];
    int ans;
    
    LL v[N];
    void add(int d,LL num){
    	if(v[d]==0)ans++;
    	v[d]+=num;
    }
    void del(int d,LL num){
    	v[d]-=num;
    	if(v[d]==0)ans--;
    }
    
    int notprime[N];
    int prime[N],cnt;
    int p[N];//p[i]表示i因数中最小的素数 
    int sn=1000;
    int split[N][3];
    int g[1007][1007];
    
    int gcd(int x,int y){
    	int ans=1,i,d;
    	for(i=0;i<3;i++){
    		if(split[x][i]<=sn) d=g[split[x][i]][y%split[x][i]];
    		else d=(y%split[x][i]==0)?split[x][i]:1;
    		ans*=d;
    		y/=d;//避免算重 
    	}
    	return ans;
    }
    
    void init_gcd(){
    	notprime[1]=1;
    	int i,j,d;
    	for(i=2;i<N;i++){
    		if(!notprime[i]){
    			prime[++cnt]=i;
    			p[i]=i;
    		}
    		for(j=1;j<=cnt;j++){
    			if((LL)prime[j]*i>=N) break;
    			d=prime[j]*i;
    			notprime[d]=1;
    			p[d]=prime[j];
    			if(i%prime[j]==0) break; 
    		}
    	}
    	
    	split[1][0]=split[1][1]=split[1][2]=1;
    	for(i=2;i<N;i++){
    		memcpy(split[i],split[i/p[i]],sizeof(split[i/p[i]]));
    		if(split[i][0]*p[i]<=sn) split[i][0]*=p[i];
    		else if(split[i][1]*p[i]<=sn) split[i][1]*=p[i];
    		else split[i][2]*=p[i];
    	}
    	
    	// gcd(0,0)=0 , gcd(0,x)=x
    	for(i=0;i<=sn;i++)
    	for(j=0;j<=i;j++){
    		if(!i||!j) g[i][j]=i|j;
    		else g[i][j]=g[j][i]=g[j][i%j];//j<=i
    	}
    }
    
    struct node{
    	int fir,d;
    }q[57];
    int tq=0;
    
    bool cmp(node x,node y){
    	if(x.d==y.d) return x.fir<y.fir;
    	else return x.d<y.d;
    }
    
    int uni(int num){
    	int i,cnt=0;
    	for(i=1;i<=num;i++)
    		if(q[i].d!=q[i-1].d) q[++cnt]=q[i];
    	return cnt;
    }
    
    void init_ans(){
    	int i,j;
    	for(i=1;i<=n;i++){
    		for(j=1;j<=tq;j++) q[j].d=gcd(q[j].d,a[i]);
    		q[++tq].d=a[i];q[tq].fir=i;
    		sort(q+1,q+tq+1,cmp);
    		tq=uni(tq);
    		for(j=1;j<tq;j++) add(q[j].d,q[j+1].fir-q[j].fir);
    		add(q[tq].d,i+1-q[tq].fir);
    	}
    }
    
    int all[M<<2];
    
    void pushup(int x){
    	all[x]=gcd(all[x<<1],all[x<<1|1]);
    }
    
    void build(int x,int l,int r){
    	if(l==r){
    		all[x]=a[l];
    		return;
    	}
    	int mid=l+r>>1;
    	build(x<<1,l,mid);
    	build(x<<1|1,mid+1,r);
    	pushup(x);
    }
    
    void update(int x,int l,int r,int to){
    	if(l==r){
    		all[x]=a[l];
    		return;
    	}
    	int mid=l+r>>1;
    	if(to<=mid) update(x<<1,l,mid,to);
    	else update(x<<1|1,mid+1,r,to);
    	pushup(x);
    }
    
    int getlf(int x,int l,int r,int tl,int tr,int G){
    	if(tl<=l&&r<=tr && all[x]%G==0) return 0;
    	if(l==r) return l;
    	int mid=l+r>>1,tp=0;
    	if(mid<tr) tp=getlf(x<<1|1,mid+1,r,tl,tr,G);
    	if(tl<=mid&&tp==0) tp=getlf(x<<1,l,mid,tl,tr,G);
    	return tp;
    }
    
    int getrt(int x,int l,int r,int tl,int tr,int &G){
    	if(tl<=l&&r<=tr && all[x]%G==0) return n+1;
    	if(l==r) return l;
    	int mid=l+r>>1,tp=n+1;
    	if(tl<=mid) tp=getrt(x<<1,l,mid,tl,tr,G);
    	if(mid<tr&&tp==n+1) tp=getrt(x<<1|1,mid+1,r,tl,tr,G);
    	return tp;
    }
    
    struct nnd{
    	int num,d;
    	nnd(int nn=0,int dd=0){num=nn;d=dd;}
    }lf[57],rt[57];
    int cl,cr;
    
    void mdf(int x,int kd){
    	int l,r,tp,nw,i,j;
    	cl=cr=0;
    	
    	l=1,r=x,nw=a[x];
    	while(l<=r){
    		tp=getlf(1,1,n,l,r,nw);
    		lf[++cl]=nnd(r-tp,nw);
    		if(tp!=0) nw=gcd(nw,a[tp]);
    		r=tp;
    	}
    	
    	l=x,r=n,nw=a[x];
    	while(l<=r){
    		tp=getrt(1,1,n,l,r,nw);
    		rt[++cr]=nnd(tp-l,nw);
    		if(tp!=n+1) nw=gcd(nw,a[tp]);
    		l=tp;
    	}
    	
    	for(i=1;i<=cl;i++)
    	for(j=1;j<=cr;j++){
    		if(kd==1) add(gcd(lf[i].d,rt[j].d),lf[i].num*rt[j].num);
    		else del(gcd(lf[i].d,rt[j].d),lf[i].num*rt[j].num);
    	}
    }
    
    int main(){
    	#ifndef ONLINE_JUDGE
    	freopen("a.in","r",stdin);
    	freopen("a.out","w",stdout);
    	#endif
    	n=rd(),m=rd();
    	int i,x,y;
    	for(i=1;i<=n;i++) a[i]=rd();
    	init_gcd();
    	init_ans();
    	build(1,1,n);
    	for(i=1;i<=m;i++){
    		x=rd(),y=rd();
    		mdf(x,-1);
    		a[x]=y;
    		update(1,1,n,x);
    		mdf(x,1);
    		printf("%d
    ",ans);
    	}
    	return 0;
    }
    

    做法2

    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cmath>
    #include <cctype>
    #include <algorithm>
    typedef long long LL;
    using namespace std;
    const int M=50007;
    const int N=57;
    
    inline int rd(){
    	int x=0;bool f=1;char c=getchar();
    	for(;!isdigit(c);c=getchar()) if(c=='-') f=0;
    	for(;isdigit(c);c=getchar()) x=x*10+c-48;
    	return f?x:-x;
    }
    
    int n,m;
    int val[M];
    
    struct node{
    	int a[N];
    };
    
    node tl[M<<2],tr[M<<2];
    int cl[M<<2],cr[M<<2],cp;
    int all[M<<2];
    
    LL num[1000007];
    int ans;
    
    int gcd(int x,int y){
    	while(y){
    		x%=y;
    		swap(x,y);
    	}
    	return x;
    }
    
    void add(int d){
    	if(num[d]==0) ans++;
    	num[d]++;
    }
    
    void del(int d){
    	num[d]--;
    	if(num[d]==0) ans--;
    }
    
    void eras(int x){
    	int lc=x<<1,rc=x<<1|1;
    	int i,j;
    	for(i=1;i<=cr[lc];i++)
    	for(j=1;j<=cl[rc];j++)
    		del(gcd(tr[lc].a[i],tl[rc].a[j]));
    }
    
    void pushup(int x){
    	int lc=x<<1,rc=x<<1|1;
    	int i,j;
    	for(i=1;i<=cr[lc];i++)
    	for(j=1;j<=cl[rc];j++)
    		add(gcd(tr[lc].a[i],tl[rc].a[j]));
    		
    	all[x]=gcd(all[lc],all[rc]);
    	
    	cl[x]=0;
    	for(i=1;i<=cl[lc];i++) tl[x].a[++cl[x]]=tl[lc].a[i];
    	for(i=1;i<=cl[rc];i++) tl[x].a[++cl[x]]=gcd(all[lc],tl[rc].a[i]);
    	sort(tl[x].a+1,tl[x].a+cl[x]+1);
    	cl[x]=unique(tl[x].a+1,tl[x].a+cl[x]+1)-(tl[x].a+1);
    	
    	cr[x]=0;
    	for(i=1;i<=cr[rc];i++) tr[x].a[++cr[x]]=tr[rc].a[i];
    	for(i=1;i<=cr[lc];i++) tr[x].a[++cr[x]]=gcd(tr[lc].a[i],all[rc]);
    	sort(tr[x].a+1,tr[x].a+cr[x]+1);
    	cr[x]=unique(tr[x].a+1,tr[x].a+cr[x]+1)-(tr[x].a+1);
    }
    
    void build(int x,int l,int r){
    	if(l==r){
    		tl[x].a[cl[x]=1]=val[l];
    		tr[x].a[cr[x]=1]=val[l];
    		all[x]=val[l];
    		add(val[l]);
    		return;
    	}
    	int mid=l+r>>1;
    	build(x<<1,l,mid);
    	build(x<<1|1,mid+1,r);
    	pushup(x);
    }
    
    void chg(int x,int l,int r,int to){
    	if(l==r){
    		del(val[l]);
    		return;
    	}
    	int mid=l+r>>1;
    	if(to<=mid) chg(x<<1,l,mid,to);
    	else chg(x<<1|1,mid+1,r,to);
    	eras(x);
    }
    
    void mdf(int x,int l,int r,int to){
    	if(l==r){
    		tl[x].a[cl[x]=1]=val[l];
    		tr[x].a[cr[x]=1]=val[l];
    		all[x]=val[l];
    		add(val[l]);
    		return;
    	}
    	int mid=l+r>>1;
    	if(to<=mid) mdf(x<<1,l,mid,to);
    	else mdf(x<<1|1,mid+1,r,to);
    	pushup(x);
    }
    
    int main(){
    	#ifndef ONLINE_JUDGE
    		freopen("a.in","r",stdin);
    		freopen("a.out","w",stdout);
    	#endif
    	int i,x,y;
    	n=rd(),m=rd();
    	for(i=1;i<=n;i++) val[i]=rd();
    	
    	build(1,1,n);
    	
    	for(i=1;i<=m;i++){
    		x=rd(),y=rd();
    		chg(1,1,n,x);
    		val[x]=y;
    		mdf(1,1,n,x);
    		printf("%d
    ",ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    HTML5 特性检测:Video Format(视频格式)
    HTML5中对script标签的规定与解释
    Java数据类型
    Java微信公众平台开发之将本地开发环境映射到公网访问
    微信扫码支付模式一和模式二的区别
    Java微信公众平台开发之获取地理位置
    Vim 的一些高频使用命令
    Python 的一些高级特性
    【面试题总结】第二篇
    Python 的模块和包
  • 原文地址:https://www.cnblogs.com/acha/p/6360444.html
Copyright © 2011-2022 走看看