SZOJ 167 Lca裸题
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SZOJ 167 Lca裸题相关的知识,希望对你有一定的参考价值。
一道.......一道我改了一周的裸题
无根树建双向边
无根树建双向边
无根树建双向边
重要的事情说三遍(微笑)
还有要开longlong
还有双向边不是双倍边(微笑)
我真是,能把自己气吐血10次就不把自己气吐血9次
【问题描述】
已知一棵nn个点的树,点从1开始标号,树上每条边都有一个正整数边权。
有qq个询问,每个询问由type,u,vtype,u,v三个正整数构成。
当type=1type=1时,询问uu到vv路径上所有边权的二进制异或和。
当type=2type=2时,询问uu到vv路径上所有边权之和。
当type=3type=3时,询问uu到vv路径上边权的最大值。
【输入格式】
第一行两个正整数n,qn,q,表示节点个数与询问数。
接下来nn-11行,每行三个正整数u,v,wu,v,w,表示编号为uu的节点与编号为vv的节点之间有一条权值为ww的边,保证给定的是一棵树。
接下来qq行,每行三个正整数type,u,vtype,u,v,表示一个询问。
【输出格式】
对每个询问输出一行表示答案。
【样例输入】
4 4
1 2 1
2 3 3
2 4 4
1 1 3
1 3 4
2 1 4
3 1 3
【样例输出】
2
7
5
3
【数据规模】
对于40%40%的数据,type=1type=1
对于80%80%的数据,type≤2type≤2
对于100%100%的数据,2≤n,q≤300000,1≤w≤109,1≤type≤32≤n,q≤300000,1≤w≤109,1≤type≤3。
对于至少25%25%的数据,树是随机生成的,这些数据会在所有测试点中比较均匀地分布。
#include<iostream> #include<cstdlib> #include<cstdio> #include<algorithm> #include<stack> #include<cstring> using namespace std; stack<int> s; int g[600001],dep[600001],n,cnt,T,q,sum2[600001]; long long sum1[600001]; int f[600001][21],g1[600001][21]; int root1; struct node{ int nxt,to,w,fr; }e[600001]; inline void addedge(int x,int y,int z){ e[++cnt].nxt=g[x];g[x]=cnt;e[cnt].to=y;e[cnt].w=z;e[cnt].fr=x; } inline void dfs(int u){ dep[u]=1;s.push(u); while(!s.empty()){ u=s.top();s.pop(); for(int i=1;i<=19;i++) f[u][i]=f[f[u][i-1]][i-1]; for(int i=1;i<=19;i++) g1[u][i]=max(g1[u][i],max(g1[f[u][i-1]][i-1],g1[u][i-1])); for(int i=g[u];i;i=e[i].nxt){ if(!dep[e[i].to]){ dep[e[i].to]=dep[u]+1; f[e[i].to][0]=u; g1[e[i].to][0]=e[i].w; s.push(e[i].to); } } } } inline int swim(int x,int h){ for(int i=0;h;i++,h>>=1) if(h&1) x=f[x][i]; return x; } inline int swim1(int x,int h){ int maxnum=-100007; for(int i=0;h;i++,h>>=1) if(h&1){ maxnum=max(maxnum,g1[x][i]); x=f[x][i]; // printf("g1=%d maxnum=%d\n",g1[x][i],maxnum); } // printf("mmmax==%d\n",maxnum); return maxnum; } inline int Lca(int x,int y){ if(dep[x]<dep[y]){ int t; t=x; x=y; y=t; } x=swim(x,dep[x]-dep[y]); if(x==y) return x; for(int i=19;~i;i--){if(f[x][i]!=f[y][i])x=f[x][i],y=f[y][i];} return f[x][0]; } inline int Lca1(int x,int y){ if(dep[x]<dep[y]){ int t; t=x; x=y; y=t; } int maxnum=swim1(x,dep[x]-dep[y]); // printf("swim1 maxnum=%d %d %d\n",maxnum,x,dep[x]-dep[y]); x=swim(x,dep[x]-dep[y]); if(x==y) return maxnum; for(int i=19;~i;i--){ if(f[x][i]!=f[y][i]){ maxnum=max(maxnum,max(g1[x][i],g1[y][i])); x=f[x][i],y=f[y][i]; } } maxnum=max(maxnum,max(g1[x][0],g1[y][0])); return maxnum; } inline void dfs1(int u){ s.push(u); while(!s.empty()){ u=s.top();s.pop(); for(int i=g[u];i;i=e[i].nxt){ if(e[i].to==f[u][0])continue; s.push(e[i].to); sum1[e[i].to]=sum1[u]+e[i].w; sum2[e[i].to]=sum2[u]^e[i].w; } } } inline void Jimmy(){ scanf("%d%d",&n,&q); for(int i=1,u,v,w;i<=n-1;i++){ scanf("%d%d%d",&u,&v,&w); addedge(u,v,w);addedge(v,u,w); } //f[1][0]=1; dfs(1); //for(int i=1;i<=n;i++)cout<<f[i][0]<<","; dfs1(1); //cout<<sum2[5]<<","<<sum2[1]<<endl; for(int i=1,u1,v1,ty;i<=q;i++){ scanf("%d%d%d",&ty,&u1,&v1); if(ty==1) printf("%d\n",sum2[u1]^sum2[v1]); if(ty==2) printf("%lld\n",sum1[u1]+sum1[v1]-2*sum1[Lca(u1,v1)]); if(ty==3) printf("%d\n",Lca1(u1,v1)); } // printf("FFFFFFFFF %d %d\n",g1[3][0],g1[3][1]); return; } int main(){ Jimmy(); return 0; }
(微笑)
以上是关于SZOJ 167 Lca裸题的主要内容,如果未能解决你的问题,请参考以下文章
BZOJ-1602: [Usaco2008 Oct]牧场行走 (LCA炒鸡大裸题)
HDU 2586 How far away ? << LCA转RMQ+ST表 求树上任两点最短距离裸题