题意:
给你n个点和n-1条边组成的一棵树,按顺序给出数的每一条边。
询问m次,每次给出一个x求x除以从点a到点b所有边的权值和的乘积,还有修改,给出边的编号,修改某条边的权值。
思路:
树链剖分,用点的编号建立线段树,当然一开始要记录第几条边的两个端点各是什么,便于修改的时候进行查询。
重点是用深度较大的那个点记录两个点之间的权值。
查询的时候当两者重链的top相等的时候注意去掉top点的权值。
然后这道题每条边的权值都是在10^18以内,所以如果线段树某个元素代表的权值之乘积大于1e18的话就直接标记成0或者别的。
#include<stdio.h> #include<string.h> #include<algorithm> using namespace std; int n,m; long long ttmp[200500]; long long INF=1e18; struct bian { int a,b; long long c; }; bian bians[200500]; struct edge { int id; long long num; edge *next; }; edge edges[200500<<1]; edge *adj[200500]; int ednum; inline void addEdge(int a,int b,long long c) { edge *tmp; tmp=&edges[ednum++]; tmp->id=b; tmp->num=c; tmp->next=adj[a]; adj[a]=tmp; } int fa[200500],top[200500],son[200500],siz[200500],id[200500],fid[200500],dep[200500]; bool vis[200500]; void dfs1(int me,int deep) { int maxsiz=-1; vis[me]=1; dep[me]=deep; siz[me]=1; for(edge *it=adj[me];it;it=it->next) { if(!vis[it->id]) { fa[it->id]=me; dfs1(it->id,deep+1); if(maxsiz<siz[it->id]) { maxsiz=siz[it->id]; son[me]=it->id; } siz[me]+=siz[it->id]; } } } int num; void dfs2(int me,int t) { vis[me]=1; top[me]=t; id[me]=++num; fid[num]=me; if(son[me]) { dfs2(son[me],t); } for(edge *it=adj[me];it;it=it->next) { if(!vis[it->id]) { dfs2(it->id,it->id); } } } struct tr { int s,e; long long num; }; tr tree[200500<<2]; long long mul(long long aaa,long long bbb) { if(aaa==0||bbb==0) return 0; if(INF/aaa<bbb) { return 0; } else return aaa*bbb; } void build(int k,int s,int e) { tree[k].s=s; tree[k].e=e; if(s==e) { tree[k].num=ttmp[fid[s]]; return; } int mid=(s+e)>>1; build(k<<1,s,mid); build(k<<1|1,mid+1,e); tree[k].num=mul(tree[k<<1].num,tree[k<<1|1].num); } long long ans; void qsum(int k,int s,int e) { if(tree[k].s==s&&tree[k].e==e) { if(fid[s]==1) return; ans=mul(ans,tree[k].num); return; } int mid=(tree[k].s+tree[k].e)>>1; if(e<=mid) { qsum(k<<1,s,e); } else if(s>mid) { qsum(k<<1|1,s,e); } else { qsum(k<<1,s,mid); qsum(k<<1|1,mid+1,e); } } inline void print(int a,int b,long long c) { ans=1; int f1=top[a],f2=top[b]; while(f1!=f2) { if(dep[f1]<dep[f2]) { swap(f1,f2); swap(a,b); } qsum(1,id[f1],id[a]); a=fa[f1]; f1=top[a]; } if(dep[a]>dep[b]) { swap(a,b); } if(id[a]+1<=id[b]) { qsum(1,id[a]+1,id[b]); } if(ans==0) printf("0 "); else printf("%I64d ",c/ans); } void updat(int k,int tar,long long c) { if(tree[k].s==tree[k].e) { tree[k].num=c; return; } int mid=(tree[k].s+tree[k].e)>>1; if(tar<=mid) { updat(k<<1,tar,c); } else { updat(k<<1|1,tar,c); } tree[k].num=mul(tree[k<<1].num,tree[k<<1|1].num); } int main() { num=0; memset(vis,0,sizeof(vis)); memset(son,0,sizeof(son)); ednum=0; scanf("%d%d",&n,&m); for(int i=1;i<n;i++) { int a,b; scanf("%d%d%I64d",&a,&b,&bians[i].c); bians[i].a=a; bians[i].b=b; addEdge(a,b,bians[i].c); addEdge(b,a,bians[i].c); } fa[1]=0; dfs1(1,1); memset(vis,0,sizeof(vis)); dfs2(1,1); for(int i=1;i<n;i++) { if(dep[bians[i].a]>dep[bians[i].b]) { ttmp[bians[i].a]=bians[i].c; } else { ttmp[bians[i].b]=bians[i].c; } } build(1,1,n); for(int i=1;i<=m;i++) { int typ,a,b; long long c; scanf("%d",&typ); if(typ==1) { scanf("%d%d%I64d",&a,&b,&c); print(a,b,c); } else { scanf("%d%I64d",&a,&c); if(dep[bians[a].a]<dep[bians[a].b]) { updat(1,id[bians[a].b],c); } else { updat(1,id[bians[a].a],c); } } } }