• 5.15 牛客挑战赛40 E 小V和gcd树 树链剖分 主席树 树状数组 根号分治


    LINK:小V和gcd树

    时限是8s 所以当时好多nq的暴力都能跑过.

    考虑每次询问暴力 跳父亲 这样是nq的 4e8左右 随便过。

    不过每次跳到某个点的时候需要得到边权 如果直接暴力gcd的话 nqlogn就过不了了。

    这里有两种解决办法:

    一种是比赛的时候队友想的 一种是比较容易想到的方法。

    前者套用树链剖分 只对重儿子的边进行修改 这样每次修改的复杂度为qlog.

    考虑查询的时候沿着重链向上跳 这样重边可以O(1)得到答案 轻边暴力。

    那么就得到了一个 nq+qlog^2的做法了。

    当然可以进行根号分治 对于度数>sqrt的点不管 对于度数<sqrt的暴力修改。

    前者在暴力跳的时候暴力查询 这样前者最多遇到sqrt(n)个这样的点 后者也是要修改sqrt次。

    所以总复杂度为 nq+qsqrt(n)log.

    两种暴力都是基于nq的暴力的。

    题解给了一个树上带修莫队的做法 不过不是很优秀复杂度接近nq的暴力 而且写起来估计也比较难写..

    对于这类问题还是考虑主席树 修改带上树状数组。

    不过这个修改是多个点的点权修改 考虑树链剖分。

    只修改重边上的信息 轻边暴力 那么利用主席树套树状数组 就可以了。

    一个比较naive的想法是 只对重链开树状数组 这样是不对的。

    考虑每次查询 是笔直的链查询 所以我们直接利用树状数组维护dfs序即可解决这个问题。

    总复杂度 qlog^3+qlog^2.这个做法还算是比较优美的。

    const int MAXN=20010;
    int n,Q,maxx,len,cnt,id,top1,top2;
    int f[MAXN],d[MAXN],a[MAXN],w[MAXN],son[MAXN],dfn[MAXN],sz[MAXN],pos[MAXN];
    int lin[MAXN],ver[MAXN<<1],nex[MAXN<<1],root[MAXN],ql[MAXN],qr[MAXN],top[MAXN];
    inline int gcd(int a,int b){return b?gcd(b,a%b):a;}
    inline void add(int x,int y)
    {
    	ver[++len]=y;nex[len]=lin[x];lin[x]=len;
    	ver[++len]=x;nex[len]=lin[y];lin[y]=len;
    }
    struct wy
    {
    	int l,r;
    	int sum;
    }t[MAXN*900];
    inline void dfs(int x,int fa)
    {
    	d[x]=d[fa]+1;f[x]=fa;sz[x]=1;
    	go(x)if(tn!=fa)
    	{
    		dfs(tn,x);
    		sz[x]+=sz[tn];
    		if(sz[tn]>sz[son[x]])son[x]=tn;
    	}
    }
    inline void dp(int x,int fa)
    {
    	top[x]=fa;dfn[x]=++cnt;pos[cnt]=x;
    	if(!son[x])return;
    	dp(son[x],fa);
    	go(x)if(tn!=f[x]&&tn!=son[x])dp(tn,tn);
    }
    inline void insert(int &p,int l,int r,int x,int y)
    {
    	if(!p)p=++id;sum(p)+=y;
    	if(l==r)return;
    	int mid=(l+r)>>1;
    	if(x<=mid)insert(l(p),l,mid,x,y);
    	else insert(r(p),mid+1,r,x,y);
    }
    inline void insert(int x,int v,int y)
    {
    	while(x<=n)
    	{
    		insert(root[x],1,maxx,v,y);
    		x+=x&(-x);
    	}
    }
    inline void modify(int x,int v)
    {
    	if(son[x])
    	{
    		insert(dfn[son[x]],w[son[x]],-1);
    		w[son[x]]=gcd(v,a[son[x]]);
    		insert(dfn[son[x]],w[son[x]],1);
    	}
    	if(f[x])
    	{
    		insert(dfn[x],w[x],-1);
    		w[x]=gcd(v,a[f[x]]);
    		insert(dfn[x],w[x],1);
    	}
    	a[x]=v;
    }
    inline int query(int l,int r,int x)//查<=x的个数.
    {
    	if(l==r)
    	{
    		int cnt=0;
    		rep(1,top1,i)cnt-=sum(ql[i]);
    		rep(1,top2,i)cnt+=sum(qr[i]);
    		return cnt;
    	}
    	int mid=(l+r)>>1;
    	if(x>mid)
    	{
    		int cnt=0;
    		rep(1,top1,i)cnt-=sum(l(ql[i]));
    		rep(1,top2,i)cnt+=sum(l(qr[i]));
    		rep(1,top1,i)ql[i]=r(ql[i]);
    		rep(1,top2,i)qr[i]=r(qr[i]);
    		return cnt+query(mid+1,r,x);
    	}
    	rep(1,top1,i)ql[i]=l(ql[i]);
    	rep(1,top2,i)qr[i]=l(qr[i]);
    	return query(l,mid,x);
    }
    inline int ask(int s1,int s2,int k)
    {
    	if(s1==s2)return 0;
    	top1=top2=0;
    	while(s1)ql[++top1]=root[s1],s1-=s1&(-s1);
    	while(s2)qr[++top2]=root[s2],s2-=s2&(-s2);
    	return query(1,maxx,k);
    }
    inline int Task(int x,int y,int k)
    {
    	int cnt=0;
    	int fx=top[x],fy=top[y];
    	while(fx!=fy)
    	{
    		if(d[fx]<d[fy])swap(x,y),swap(fx,fy);
    		cnt+=ask(dfn[fx],dfn[x],k);
    		int ww=gcd(a[fx],a[f[fx]]);
    		cnt+=(ww<=k);
    		x=f[fx];fx=top[x];
    	}
    	if(d[x]<d[y])swap(x,y);
    	cnt+=ask(dfn[y],dfn[x],k);
    	return cnt;
    }
    int main()
    {
    	//freopen("1.in","r",stdin);
    	get(n);get(Q);maxx=1000000;
    	rep(1,n,i)get(a[i]);
    	rep(2,n,i)add(read(),read());
    	dfs(1,0);dp(1,1);
    	rep(2,n,i)insert(dfn[i],w[i]=gcd(a[i],a[f[i]]),1);
    	rep(1,Q,i)
    	{
    		int op,x;
    		get(op);get(x);
    		if(op==1)modify(x,read());
    		else
    		{
    			int get(v);
    			put(Task(x,v,read()));
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    ansible register 之用法
    vim 多行注释和取消注释
    开启 ssh 的 root 登录
    HAproxy 添加多个配置文件
    1002. A+B for Polynomials (25)
    Java中浮点数能连续精确表示整数的范围
    1001. A+B Format (20)
    1003. 我要通过!(20)
    1009. 说反话 (20)
    1006. 换个格式输出整数 (15)
  • 原文地址:https://www.cnblogs.com/chdy/p/12925491.html
Copyright © 2020-2023  润新知