首页 > 代码库 > HDU 5044 (树链剖分+树状数组+点/边改查)
HDU 5044 (树链剖分+树状数组+点/边改查)
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5044
题目大意:修改链上点,修改链上的边。查询所有点,查询所有边。
解题思路:
2014上海网赛的变态树链剖分模板题。将以往树链剖分的点&边修改和查询合在一起之后,难度上去不少。
第一个卡人点是读入优化。
第二个卡人点是树状数组。由于要查询所有点,如果使用线段树,每次都要扫到底层才能取出点值,必T无疑。
然后使用树状数组之后,树链剖分的点/边修改写法有些变动。
点查询变化不大。
边查询只要查询一下dep(u,v)大的那一端。
具体变化请仔细看代码。
#pragma comment(linker, "/STACK:1024000000,1024000000")#include "cstdio"#include "cstring"#include "iostream"using namespace std;#define maxn 100005template <class T>inline bool read(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;}int s[maxn],dep[maxn],w[maxn],fa[maxn],top[maxn],son[maxn],tol,cnt,n,head[maxn];struct Edge{ int u,v,c;}edge[maxn];struct EDGE{ int next,to;}e[2*maxn];void addedge(int u,int v){ e[tol].to=v; e[tol].next=head[u]; head[u]=tol++;}void dfs1(int u,int pre,int d){ s[u]=1;fa[u]=pre;dep[u]=d;son[u]=-1; for(int i=head[u];i!=-1;i=e[i].next) { int v=e[i].to; if(v==pre) continue; dfs1(v,u,d+1); s[u]+=s[v]; if(son[u]!=-1||s[v]>s[son[u]]) son[u]=v; }}void dfs2(int u,int tp){ w[u]=++cnt;top[u]=tp; if(son[u]!=-1) dfs2(son[u],tp); for(int i=head[u];i!=-1;i=e[i].next) { int v=e[i].to; if(v!=son[u]&&v!=fa[u]) dfs2(v,v); }}//Binary-Indexed-Tree type:0-point,1-edgeint psum[maxn],esum[maxn];inline int lowbit(int x) {return x&(-x);}int sum(int x,int type){ int ret=0; while(x>0) { if(!type) ret+=psum[x]; else ret+=esum[x]; x-=lowbit(x); } return ret;}void add(int x,int d,int type){ while(x<=n) { if(!type) psum[x]+=d; else esum[x]+=d; x+=lowbit(x); }}void p_Change(int x,int y,int v){ while(top[x]!=top[y]) { if(dep[top[x]]<dep[top[y]]) swap(x,y); add(w[top[x]],v,0); add(w[x]+1,-v,0); x=fa[top[x]]; } if(dep[x]>dep[y]) swap(x,y); add(w[x],v,0); add(w[y]+1,-v,0);}void e_Change(int x,int y,int v){ while(top[x]!=top[y]) { if(dep[top[x]]<dep[top[y]]) swap(x,y); add(w[top[x]],v,1); add(w[x]+1,-v,1); x=fa[top[x]]; } if(dep[x]>dep[y]) swap(x,y); if(x!=y) //这个判断非常重要,没有的话T死你 { add(w[son[x]],v,1); add(w[y]+1,-v,1); }}int main(){ //freopen("in.txt","r",stdin); int T,u,v,c,m,no=0; char cmd[10]; read(T); while(T--) { memset(head,-1,sizeof(head)); memset(esum,0,sizeof(esum)); memset(psum,0,sizeof(psum)); tol=cnt=0; read(n);read(m); for(int i=1;i<n;i++) { read(edge[i].u);read(edge[i].v); addedge(edge[i].u,edge[i].v); addedge(edge[i].v,edge[i].u); } dfs1(1,1,1); dfs2(1,1); for(int i=1;i<n;i++) if(dep[edge[i].u]<dep[edge[i].v]) swap(edge[i].u,edge[i].v); while(m--) { scanf("%s",cmd); read(u);read(v);read(c); if(cmd[3]==‘1‘) p_Change(u,v,c); if(cmd[3]==‘2‘) e_Change(u,v,c); } printf("Case #%d:\n",++no); for(int i=1;i<=n;i++) {if(i>=2) printf(" ");printf("%d",sum(w[i],0));} printf("\n"); for(int i=1;i<n;i++) {if(i>=2) printf(" ");printf("%d",sum(w[edge[i].u],1));} printf("\n"); }}
11824525 | 2014-10-08 17:34:00 | Accepted | 5044 | 3718MS | 11576K | 3384 B | C++ | Physcal |
HDU 5044 (树链剖分+树状数组+点/边改查)
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。