题意:一初始无权的二叉树(第i歌节点有2条边 i-2i i-2i+1),节点个数最多10^18 给出2个操作1 u v w 表示给 u->v 路径上的每一条边加上w的权值 2 u v 表示询问u->v的路径的权值和
思路:给每个节点设置2个点权 左孩子点权l 和右孩子点权r 每次操作沿路径修改点权 或累加权值和
AC代码:
#include"stdio.h" #include"math.h" #include"map" #include"string.h" #include"iostream" #include"algorithm" #define ll long long using namespace std; struct Node{ ll l,r; Node(){ l=0,r=0; } }; map<ll,Node> M; int getcc(ll x){ int ans=0; while(x){ x>>=1; ans++; } return ans; } int main(){ ll q,f,u,v,w; cin>>q; for(int k=0; k<q; ++k){ scanf("%lld",&f); if(f==1){ scanf("%lld%lld%lld",&u,&v,&w); int gu=getcc(u), gv=getcc(v); if(gu<gv){ swap(u,v); swap(gu,gv); } while(gu>gv){ if(u&1) M[u].r+=w; else M[u].l+=w; u>>=1; gu--; } while(u!=v){ if(u&1) M[u].r+=w; else M[u].l+=w; u>>=1; if(v&1) M[v].r+=w; else M[v].l+=w; v>>=1; } } else{ scanf("%lld%lld",&u,&v); ll ans=0; int gu=getcc(u),gv=getcc(v); if(gu<gv){ swap(u,v); swap(gu,gv); } while(gu>gv){ if(u&1) ans+=M[u].r; else ans+=M[u].l; u>>=1; gu--; } while(u!=v){ if(u&1) ans+=M[u].r; else ans+=M[u].l; if(v&1) ans+=M[v].r; else ans+=M[v].l; u>>=1,v>>=1; } cout<<ans<<endl; } } return 0; }