zoukankan      html  css  js  c++  java
  • LOJ576签到游戏

    题目的询问是个经典模型。
    (s_i=a_1+a_2+...+a_i)(前缀和),则我们询问一下能够得到(s_r-s_{l-1})
    考虑图(0...n)的一个生成树,边((l,r))的代价是(gcd(a_{l+1}...a_r))
    显然我们得知了生成树,即可推出所有(s),所以我们要求最小生成树。
    但是直接mst会超时。
    考虑画图,画图后会发现一个点要么连向(0),要么连向(n)
    由于一个点不能连出自环,所以显然(0)要连向(n)
    其他点显然我们会选择边权最小的点连接。
    考虑把所有后缀,前缀(gcd)相同连续段抽出来。只有(log_2)种。
    则考虑扫描线。显然可以轻松的计算出代价。
    现在考虑怎么得知(gcd)相同连续段。
    显然可以每次线段树二分。
    好像直接暴力(gcd)时间复杂度就是对的。
    然而T了。改成取模就过了

    #include<bits/stdc++.h>
    using namespace std;
    #define N 400010
    #define int long long
    int gcd(int a,int b){
    	if(!b)
    		return a;
    	return gcd(b,a%b);
    }
    int n,q,b[N],g[N],p[N],s[N],e[N],f[N],ct,rr[N],h[N],cc,v1[N],v2[N];
    int fd(int x){
    	return p[x]==x?x:p[x]=fd(p[x]);
    }
    struct no{
    	int x,y,z;
    }a[N];
    struct nn{
    	int l,r,v;
    }c[N],d[N];
    int operator <(no x,no y){
    	return x.z<y.z;
    }
    void up(int o){
    	g[o]=gcd(g[o*2],g[o*2+1]);
    }
    void bd(int o,int l,int r){
    	if(l==r){
    		g[o]=b[l];
    		return;
    	}
    	int md=(l+r)/2;
    	bd(o*2,l,md);
    	bd(o*2+1,md+1,r);
    	up(o);
    }
    void mod(int o,int l,int r,int x,int y){
    	if(l==r){
    		g[o]=y;
    		return;
    	}
    	int md=(l+r)/2;
    	if(x<=md)
    		mod(o*2,l,md,x,y);
    	else
    		mod(o*2+1,md+1,r,x,y);
    	up(o);
    }
    int gt(){
    	int ct=0,v=0;
    	for(int i=0;i<=n;i++)
    		p[i]=i;
    	for(int i=1;i<=n;i++)
    		v=gcd(v,b[i]);
    	a[++ct]=(no){0,n,v};
    	int ans=0;
    	v=0;
    	for(int i=1;i<n;i++){
    		v=gcd(v,b[i]);
    		a[++ct]=(no){0,i,v};
    	}
    	v=0;
    	for(int i=n;i>1;i--){
    		v=gcd(v,b[i]);
    		a[++ct]=(no){i-1,n,v};
    	}
    	sort(a+1,a+ct+1);
    	for(int i=1;i<=ct;i++){
    		int xx=fd(a[i].x),yy=fd(a[i].y);
    		if(xx!=yy){
    			p[xx]=yy;
    			ans+=a[i].z;
    		}
    	}
    	return ans;
    }
    void fd(int o,int l,int r,int x,int y){
    	if(r<x||y<l)
    		return;
    	if(x<=l&&r<=y){
    		s[++ct]=g[o];
    		e[ct]=l;
    		f[ct]=r;
    		rr[ct]=o;
    		return;
    	}
    	int md=(l+r)/2;
    	fd(o*2,l,md,x,y);
    	fd(o*2+1,md+1,r,x,y);
    }
    int e1(int o,int l,int r,int c){
    	if(l==r)
    		return l;
    	int md=(l+r)/2;
    	if(g[o*2]%c!=0)
    		return e1(o*2,l,md,c);
    	else
    		return e1(o*2+1,md+1,r,c);
    }
    int e2(int o,int l,int r,int c){
    	if(l==r)
    		return l;
    	int md=(l+r)/2;
    	if(g[o*2+1]%c!=0)
    		return e2(o*2+1,md+1,r,c);
    	else
    		return e2(o*2,l,md,c);
    }
    int f1(int x,int g,int lp){
    	ct=0;
    	fd(1,1,n,x,n);
    	int v=0;
    	for(int i=1;i<=ct;i++)
    		v=gcd(v,s[i]);
    	v=gcd(v,lp);
    	if(v%g==0)
    		return -1;
    	for(int i=1;i<=ct;i++){
    		int p=gcd(lp,s[i]);
    		if(p!=g)
    			return e1(rr[i],e[i],f[i],g);
    		lp=p;
    	}
    }
    int f2(int x,int g,int lp){
    	ct=0;
    	fd(1,1,n,1,x);
    	int v=0;
    	for(int i=1;i<=ct;i++)
    		v=gcd(v,s[i]);
    	v=gcd(v,lp);
    	if(v%g==0)
    		return -1;
    	for(int i=ct;i;i--){
    		int p=gcd(lp,s[i]);
    		if(p!=g)
    			return e2(rr[i],e[i],f[i],g);
    		lp=p;
    	}
    }
    signed main(){
    	scanf("%lld%lld",&n,&q);
    	for(int i=1;i<=n;i++)
    		scanf("%lld",&b[i]);
    	if(n*q<=100000){
    		for(int i=1;i<=q;i++){
    			int x,y;
    			scanf("%lld%lld",&x,&y);
    			b[x]=y;
    			printf("%lld
    ",gt());
    		}
    		return 0;
    	}
    	bd(1,1,n);
    	while(q--){
    		int x,y;
    		scanf("%lld%lld",&x,&y);
    		mod(1,1,n,x,y);
    		b[x]=y;
    		cc=0;
    		int p=1,la=0,c1=0,c2=0,gg=b[1],c3=0,c4=0,lp=0;
    		while(p!=-1){
    			la=p;
    			p=f1(p,gg,lp);
    			if(p==-1){
    				if(la<=n)
    					c[++c1]=(nn){la,n,gg};
    				break;
    			}
    			if(la<n)
    				c[++c1]=(nn){la,p-1,gg};
    			gg=gcd(gg,b[p]);
    			lp=gcd(lp,b[la]);
    		}
    		p=n;
    		la=n;
    		gg=b[n];
    		lp=0;
    		while(p!=-1){
    			la=p;
    			p=f2(p,gg,lp);
    			if(p==-1){
    				if(la)
    					d[++c2]=(nn){1,la,gg};
    				break;
    			}
    			if(la)
    				d[++c2]=(nn){p+1,la,gg};
    			gg=gcd(gg,b[p]);
    			lp=gcd(lp,b[la]);
    		}
    		for(int i=1;i<=c2;i++){
    			d[i].l--;
    			d[i].r--;
    			d[i].l=max(d[i].l,1ll);
    		}
    		for(int i=1;i<=c1;i++){
    			h[++cc]=c[i].l;
    			h[++cc]=c[i].r+1;
    		}
    		for(int i=1;i<=c2;i++){
    			h[++cc]=d[i].l;
    			h[++cc]=d[i].r+1;
    		}
    		int ans=0;
    		sort(h+1,h+cc+1);
    		h[cc+1]=n;
    		cc=unique(h+1,h+cc+1)-h-1;
    		for(int i=1;i<=c1;i++){
    			c[i].l=lower_bound(h+1,h+cc+1,c[i].l)-h;
    			c[i].r=upper_bound(h+1,h+cc+1,c[i].r)-h-1;
    		}
    		for(int i=1;i<=c2;i++){
    			d[i].l=lower_bound(h+1,h+cc+1,d[i].l)-h;
    			d[i].r=upper_bound(h+1,h+cc+1,d[i].r)-h-1;
    		}
    		for(int i=1;i<=c1;i++)
    			for(int j=c[i].l;j<=c[i].r;j++)
    				v1[j]=c[i].v;
    		for(int i=1;i<=c2;i++)
    			for(int j=d[i].l;j<=d[i].r;j++)
    				v2[j]=d[i].v;
    		for(int i=1;i<=cc;i++)
    			ans+=max(0ll,min(h[i+1],n)-h[i])*min(v1[i],v2[i]);
    		for(int i=1;i<=cc;i++)
    			v1[i]=v2[i]=h[i]=0;
    		printf("%lld
    ",ans+g[1]);
    	}
    	puts("");
    }
    
  • 相关阅读:
    反射 动态导入 元类
    面向对象的继承
    面向对象基础总结
    面向对象基础
    包 logging hashlib copy模块
    os random sys json 模块
    【1012 | Day 43】前端之CSS(下)
    【1011 | Day 42】灵魂拷问:数据放在服务端和客户端的利与弊?
    【1011 | Day 42】socket实现ftp文件的上传和下载
    【1011 | Day 42】前端之CSS(上)
  • 原文地址:https://www.cnblogs.com/ctmlpfs/p/14153078.html
Copyright © 2011-2022 走看看