CF #329 D
D题,LCA是很明显的。要注意的是,因为是除法,所以最多可以除x>2的有64次,当大于64时可以直接返回0。而且注意到可能会有很多值为1的边,可以使用路径压缩,把边为1的边压缩掉,类似于并查集的路径压缩。
之前只压缩到LCA,一直TLE,可以直接压缩到它们的根节点。
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <queue> #include <cmath> #define LL long long using namespace std; const int MAX=200050; int head[MAX],tot; struct Edge{ int u,v,next; LL w; }edge[MAX*2]; LL w[MAX]; int pre[MAX],depth[MAX],edno[MAX],par[MAX][20]; bool vis[MAX]; queue<int>que; void addedge(int u,int v,LL w){ edge[tot].u=u; edge[tot].v=v; edge[tot].w=w; edge[tot].next=head[u]; head[u]=tot++; } int n,m; void BFS(int u){ que.push(u); depth[u]=1; edno[u]=0; while(!que.empty()){ u=que.front(); vis[u]=true; que.pop(); for(int e=head[u];e!=-1;e=edge[e].next){ int v=edge[e].v; if(vis[v]) continue; depth[v]=depth[u]+1; par[v][0]=u; if(w[edno[u]]==1){ pre[v]=pre[u]; edno[v]=edge[e].w; } else{ pre[v]=u; edno[v]=edge[e].w; } que.push(v); } } } void init(){ int i,j; for(j=1;(1<<j)<=n;j++) for(i=1;i<=n;i++) if(par[i][j-1]!=-1) par[i][j]=par[par[i][j-1]][j-1]; } int LCA(int a,int b)//最近公共祖先 { int i,j; if(depth[a]<depth[b])swap(a,b); for(i=0;(1<<i)<=depth[a];i++); i--; //使a,b两点的深度相同 for(j=i;j>=0;j--) if(depth[a]-(1<<j)>=depth[b]) a=par[a][j]; if(a==b)return a; //倍增法,每次向上进深度2^j,找到最近公共祖先的子结点 for(j=i;j>=0;j--){ if(par[a][j]!=-1&&par[a][j]!=par[b][j]){ a=par[a][j]; b=par[b][j]; } } return par[a][0]; } LL anum[70]; LL bnum[70]; LL query(int a,int b,LL y){ int ret=(int)(log((double)y)/log(2.0)); int lca=LCA(a,b); /// cout<<lca<<" "<<ret<<endl; int ac=0,bc=0; while(a!=-1&&depth[a]>depth[lca]){ //// cout<<a<<" "<<w[edno[a]]<<endl; if(w[edno[a]]>1){ y/=w[edno[a]]; if(y==0) return 0; } int tp=pre[a]; while(pre[tp]!=-1&&w[edno[tp]]==1){ tp=pre[tp]; } int rt=tp; tp=a; while(pre[tp]!=rt){ int tmp=pre[tp]; pre[tp]=rt; tp=tmp; } a=rt; } LL ty=y; while(b!=-1&&depth[b]>depth[lca]){ /// cout<<b<<" "<<edno[b]<<endl; if(w[edno[b]]>1){ ty/=w[edno[b]]; bnum[bc++]=w[edno[b]]; if(ty==0) return 0; } int tp=pre[b]; while(pre[tp]!=-1&&w[edno[tp]]==1){ tp=pre[tp]; } int rt=tp; tp=b; while(pre[tp]!=rt){ int tmp=pre[tp]; pre[tp]=rt; tp=tmp; } b=rt; } /// cout<<ac<<" "<<bc<<endl; /// cout<<bnum[bc-1]<<endl; /// for(int i=0;i<ac;i++) y/=anum[i]; for(int i=bc-1;i>=0;i--) y/=bnum[i]; return y; } int main(){ int u,v,op,a,b,p,c; LL y; while(scanf("%d%d",&n,&m)!=EOF){ memset(pre,-1,sizeof(pre)); memset(head,-1,sizeof(head)); memset(depth,0,sizeof(depth)); memset(vis,false,sizeof(vis)); memset(w,0,sizeof(w)); memset(par,-1,sizeof(par)); memset(edno,0,sizeof(edno)); tot=0; for(int i=1;i<n;i++){ cin>>u>>v>>w[i]; addedge(u,v,i); addedge(v,u,i); } BFS(1); /// cout<<pre[2]<<" "<<edno[2]<<endl; init(); for(int i=1;i<=m;i++){ scanf("%d",&op); if(op==1){ cin>>a>>b>>y; cout<<query(a,b,y)<<endl; } else{ cin>>p>>y; w[p]=y; } } } return 0; }