hdu 5044 树区间操作最后输出/ lca+dfs
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了hdu 5044 树区间操作最后输出/ lca+dfs相关的知识,希望对你有一定的参考价值。
题意:一棵树,俩种操作:1 有路径上的全部点加vi,2全部边加vi。
先离线求出全部询问的lca,再遍历询问一次,点+vi,lca-2*vi ,最后dfs从叶子扫上来一次,最后再祖先点补上就可以。用了输入挂。
复杂度(n+m).
#pragma comment(linker,"/STACK:10240000000000,10240000000000") #include<iostream> #include<cstdio> #include<cstdlib> using namespace std; const int maxv=100005,maxe=200015; int head[maxv];int nume=0;long long e[maxe][3]; void inline adde(int i,int j) //边 { e[nume][0]=j;e[nume][1]=head[i];head[i]=nume; e[nume++][2]=0; e[nume][0]=i;e[nume][1]=head[j];head[j]=nume; e[nume++][2]=0; } int headq[maxv];int numq=0;long long q[maxe][5]; void inline addq(int x,int y,long long vals,int flag) //询问 { q[numq][0]=y;q[numq][1]=headq[x];headq[x]=numq; q[numq][2]=-1;q[numq][3]=vals;q[numq++][4]=flag; q[numq][0]=x;q[numq][1]=headq[y];headq[y]=numq; q[numq][2]=-1;q[numq][3]=vals;q[numq++][4]=flag; } int fa[maxv]; int find(int x) { if(x!=fa[x]) return fa[x]=find(fa[x]); return fa[x]; } int ve[maxv]; int n,m; int vis[maxv];int vis2[maxv]; long long val[maxv]; int ise[maxe]; void tarjan(int u,int father) //离线求lca { for(int j=head[u];j!=-1;j=e[j][1]) { int v=e[j][0]; if(!vis[v]&&v!=father) { ve[v]=j; ise[j]=1; tarjan(v,u); fa[v]=u; } } vis[u]=1; for(int j=headq[u];j!=-1;j=q[j][1]) { if(vis[q[j][0]]) { q[j^1][2]=q[j][2]=find(q[j][0]); } } } void dfs(int u) //求出全部点边情况 { for(int j=head[u];j!=-1;j=e[j][1]) { int v=e[j][0]; if(!vis2[v]) { vis2[v]=1; dfs(v); val[u]+=val[v]; e[ve[u]][2]+=e[ve[v]][2]; } } } int vis_e[maxe]; long long anster[maxv]; void init() { nume=numq=0; for(int i=0;i<maxv;i++) { head[i]=headq[i]=-1; fa[i]=i; val[i]=vis2[i]=vis[i]=0; ve[i]=2*n; anster[i]=0; } for(int i=0;i<maxe;i++) { ise[i]=0; vis_e[i]=0; } } template <class T> //输入挂 inline bool scan(T &ret) { char c; int sgn; if(c=getchar(),c==EOF) return 0; //EOF while(c!=‘-‘&&(c<‘0‘||c>‘9‘)) c=getchar(); sgn=(c==‘-‘)?-1:1; ret=(c==‘-‘)?0:(c-‘0‘); while(c=getchar(),c>=‘0‘&&c<=‘9‘) ret=ret*10+(c-‘0‘); ret*=sgn; return 1; } /*inline void prints(long long x) { if(x>9) prints(x/10); putchar(x%10+‘0‘); }*/ int main() { int T;int cnt=1; scan(T); //scanf("%d",&T); while(T--) { //scanf("%d%d",&n,&m); scan(n);scan(m); init(); int aa,bb,cc; for(int i=0;i<n-1;i++) { // scanf("%d%d",&aa,&bb); scan(aa);scan(bb); adde(aa,bb); } int tx; for(int i=0;i<m;i++) { getchar();getchar();getchar();//getchar(); //scanf("ADD"); scan(tx); scan(aa);scan(bb);scan(cc); // scanf("%d%d%d%d",&tx,&aa,&bb,&cc); if(tx==1) addq(aa,bb,cc,1); else addq(aa,bb,cc,0); } tarjan(n/2+1,-1); for(int i=1;i<=n;i++) for(int j=headq[i];j!=-1;j=q[j][1]) { if(!vis_e[j]) { vis_e[j]=vis_e[j^1]=1; if(q[j][4]) { val[i]+=q[j][3]; val[q[j][0]]+=q[j][3]; val[q[j][2]]-=q[j][3]*2; anster[q[j][2]]+=q[j][3]; } else { e[ve[i]][2]+=q[j][3]; e[ve[q[j][0]]][2]+=q[j][3]; e[ve[q[j][2]]][2]-=2*q[j][3]; } } } vis2[n/2+1]=1; dfs(n/2+1); printf("Case #%d:\n",cnt++); for(int i=1;i<n;i++) printf("%I64d ",val[i]+anster[i]); printf("%I64d\n",val[n]+anster[n]); for(int j=0;j<nume;j++) if(ise[j]) { if(j==nume-2||j==nume-1)printf("%I64d",e[j][2]); else printf("%I64d ",e[j][2]); } puts(""); } return 0; }
以上是关于hdu 5044 树区间操作最后输出/ lca+dfs的主要内容,如果未能解决你的问题,请参考以下文章
L - Vases and Flowers HDU - 4614 线段树+二分