• Jzoj4846 行走


    这个题一看就是树剖的模型

    但是有一些问题,比如权值的乘机太大了,可能会爆long long

    一种解决的方法:我们考虑到,v<=10^18 所以最多经过60条大于1的边

    对于权值为1的边我们可以用一个并查集合并(注意只会改小)

    但是这种方法不好想,我们还是考虑树剖

    若权值>=10^18 我们可以直接将其变为一个特殊的值(例如-1)表示“足够大”,这种情况直接输出0

    若不够,我们有一个结论: [[a/b]/c] = [a/bc] 这个是显然的,所以可以将路径上的权值乘机求出并直接得到答案

    CODE比较长但是比较好想(mul()这里做乘法的时候会爆long long ,一种方法是用除法,但是效率比较低所以用了int128)

    #include<stdio.h>
    #include<string.h>
    #include<algorithm>
    #define N 100010
    #define mid (l+r>>1) 
    #define LL __int128
    #define M 1000000000000000000ll 
    using namespace std;
    struct Edge{ int v,nt; LL c; } G[N<<1];
    int h[N],sz[N],son[N],d[N],f[N],rk[N];
    int top[N],b[N],n,m,cnt=0,clk=0; LL w[N<<2],val[N]; long long C,D;
    LL mul(LL x,LL y){ return ~x&&~y?(x*y>=M?-1:x*y):-1; }
    inline void adj(int x,int y,LL c){
    	G[++cnt]=(Edge){y,h[x],c}; h[x]=cnt;
    }
    void dfs(int x,int p){
    	f[x]=p; sz[x]=1; d[x]=d[p]+1;
    	for(int v,i=h[x];i;i=G[i].nt)
    		if((v=G[i].v)!=p){
    			dfs(v,x); val[v]=G[i].c;
    			sz[x]+=sz[v];
    			if(sz[v]>sz[son[x]]) son[x]=v;
    		}
    }
    void dijk(int x,int p){
    	b[x]=++clk; rk[clk]=x; top[x]=p;
    	if(son[x]) dijk(son[x],p);
    	for(int v,i=h[x];i;i=G[i].nt)
    		if((v=G[i].v)!=f[x] && v!=son[x]) dijk(v,v);
    }
    void build(int l,int r,int x){
    	if(l==r){ w[x]=val[rk[l]]; return; }
    	build(l,mid,x<<1);
    	build(mid+1,r,x<<1|1);
    	w[x]=mul(w[x<<1],w[x<<1|1]); 
    }
    void update(int l,int r,int x,int p,LL k){
    	if(l==r){ w[x]=k; return; }
    	if(p<=mid) update(l,mid,x<<1,p,k); 
    	  else update(mid+1,r,x<<1|1,p,k);
    	w[x]=mul(w[x<<1],w[x<<1|1]);
    }
    LL query(int l,int r,int x,int L,int R){
    	if(L<=l && r<=R) return w[x];
    	LL ans=1;
    	if(L<=mid) ans=mul(ans,query(l,mid,x<<1,L,R));
    	if(mid<R) ans=mul(ans,query(mid+1,r,x<<1|1,L,R));
    	return ans;
    }
    LL gLca(int x,int y){
    	LL A=1;
    	for(;top[x]!=top[y]&&~A;y=f[top[y]]){
    		if(d[top[x]]>d[top[y]]) swap(x,y);
    		A=mul(A,query(1,n,1,b[top[y]],b[y]));
    	}
    	if(d[x]>d[y]) swap(x,y);
    	A=mul(A,query(1,n,1,b[x]+1,b[y]));
    	return A;
    }
    int main(){
    	freopen("walk.in","r",stdin);
    	freopen("walk.out","w",stdout);
    	scanf("%d%d",&n,&m);
    	for(int x,y,i=1;i<n;++i){
    		scanf("%d%d%lld",&x,&y,&C);
    		adj(x,y,C); adj(y,x,C);
    	}
    	dfs(1,0); dijk(1,1); build(1,n,1);
    	for(int o,x,y;m--;){
    		scanf("%d",&o);
    		if(o==1){
    			scanf("%d%d%lld",&x,&y,&C);
    			D=gLca(x,y);
    			if(D==-1 || D>C) puts("0");
    			else printf("%lld
    ",C/D);
    		} else {
    			scanf("%d%lld",&x,&C);
    			y=G[x<<1].v; x=G[(x<<1)-1].v;
    			if(f[y]==x) x=y;
    			update(1,n,1,b[x],C);
    		}
    	}
    }

  • 相关阅读:
    什么是Swap Chain【转自MSDN】
    【转】Foobar 2000设置replay gain
    openGL library下载地址
    C++函数返回含堆数据的对象时,内存释放问题
    [原]VS2008安装boost的lib库
    【转】水木社区VIM版版友推荐插件列表
    Css学习总结(1)——20个很有用的CSS技巧
    Css学习总结(1)——20个很有用的CSS技巧
    Git学习总结(2)——初识 GitHub
    Git学习总结(2)——初识 GitHub
  • 原文地址:https://www.cnblogs.com/Extended-Ash/p/9477263.html
Copyright © 2020-2023  润新知