COJ 0970 WZJ的数据结构(负三十)树分治
2015-08-07 21:57
567 查看
WZJ的数据结构(负三十) |
难度级别:D; 运行时间限制:1000ms; 运行空间限制:262144KB; 代码长度限制:2000000B |
试题描述 |
给你一棵N个点的无根树,点和边上均有权值。请你设计一个数据结构,回答M次操作。 1 x v:对于树上的每一个节点y,如果将x、y在树上的距离记为d,那么将y节点的权值加上d*v。 2 x:询问节点x的权值。 |
输入 |
第一行为一个正整数N。 第二行到第N行每行三个正整数ui,vi,wi。表示一条树边从ui到vi,距离为wi。 第N+1行为一个正整数M。 最后M行每行三个或两个正整数,格式见题面。 |
输出 |
对于每个询问操作,输出答案。 |
输入示例 |
10 1 2 2 1 3 1 1 4 3 1 5 2 4 6 2 4 7 1 6 8 1 7 9 2 7 10 1 9 1 3 1 1 10 1 2 1 2 4 2 5 1 5 1 1 8 1 2 2 2 9 |
输出示例 |
6 6 10 22 24 |
其他说明 |
对于30%的数据:1<=N,M<=1000 另有50%的数据:1<=N,M<=100000,保证修改操作均在询问操作之前。 对于100%的数据:1<=N,M<=100000,1<=x<=N,1<=v,wi<=1000 |
#include<iostream> #include<cstdio> #include<cmath> #include<algorithm> #include<queue> #include<cstring> #define PAU putchar(' ') #define ENT putchar('\n') using namespace std; const int maxn=100000+10,maxm=200000+10,inf=-1u>>1; int n,Q,A[maxn],CG,f[maxn],siz[maxn],size;bool vis[maxn]; struct ted{int x,y,w;ted*nxt;}adj[maxm],*fch[maxn],*ms=adj; void add(int x,int y,int w){ *ms=(ted){x,y,w,fch[x]};fch[x]=ms++; *ms=(ted){y,x,w,fch[y]};fch[y]=ms++; return; } long long ans[maxn],sum,sumd,tsum,tsumd; void findcg(int x,int fa){ siz[x]=1;int mxs=0; for(ted*e=fch[x];e;e=e->nxt){ int v=e->y;if(v!=fa&&!vis[v]){ findcg(v,x);siz[x]+=siz[v];mxs=max(mxs,siz[v]); } }f[x]=max(mxs,size-siz[x]);if(f[x]<f[CG])CG=x;return; } void dfs(int x,int fa,int dis){ //printf("(%d,%d) ",x,dis); siz[x]=1;tsum+=A[x]*dis;tsumd+=A[x];ans[x]+=dis*sumd+sum; for(ted*e=fch[x];e;e=e->nxt){ int v=e->y;if(v!=fa&&!vis[v]){ dfs(v,x,dis+e->w);siz[x]+=siz[v]; } }return; } void solve(int x=CG){ //printf("--------%d---------\n",x); vis[x]=true;sum=0;sumd=A[x];static ted*s[maxm];int top=0; for(ted*e=fch[x];e;e=e->nxt){ s[top++]=e;int v=e->y; if(!vis[v])tsum=tsumd=0,dfs(v,x,e->w),sum+=tsum,sumd+=tsumd; //puts(""); }ans[x]+=sum;sum=0;sumd=0; while(top--){ ted*e=s[top];int v=e->y;if(!vis[v])tsum=tsumd=0,dfs(v,x,e->w),sum+=tsum,sumd+=tsumd;//puts(""); } for(ted*e=fch[x];e;e=e->nxt){ int v=e->y;if(!vis[v]){ f[CG=0]=size=siz[v];findcg(v,x);solve(); } }return; } inline int read(){ int x=0,sig=1;char ch=getchar(); while(!isdigit(ch)){if(ch=='-')sig=-1;ch=getchar();} while(isdigit(ch))x=10*x+ch-'0',ch=getchar(); return x*=sig; } inline void write(int x){ if(x==0){putchar('0');return;}if(x<0)putchar('-'),x=-x; int len=0,buf[15];while(x)buf[len++]=x%10,x/=10; for(int i=len-1;i>=0;i--)putchar(buf[i]+'0');return; } void init(){ n=read();int x,y; for(int i=1;i<n;i++)x=read(),y=read(),add(x,y,read()); return; } int Qs[maxn],M; void work(){ Q=read();int tp,x; while(Q--){ tp=read();x=read(); if(tp==1)A[x]+=read(); else Qs[++M]=x; } f[CG=0]=size=n;findcg(1,0);solve(); for(int i=1;i<=M;i++)printf("%lld\n",ans[Qs[i]]); return; } void print(){ return; } int main(){init();work();print();return 0;} /* 10 1 2 2 1 3 1 1 4 3 1 5 2 4 6 2 4 7 1 6 8 1 7 9 2 7 10 1 6 1 3 1 1 10 1 1 5 1 1 8 1 2 2 2 9 */
动态树做法:%%%小健健,动态树分治其实就是把重心累成一棵树,这棵树保证了树高logn。窝萌把信息分三份累加在覆盖这个操作点的最多logn个重心上,分别是整棵子树的信息all,本子树到重心的父亲的距离信息cha %&!。。。(意会意会。。。),本子树到重心的距离信息tre @*%¥%……。。。(意会意会。。。)
有几个tips!
1.窝萌的一切操作都是在重心树上进行的!
2.tre,cha,all这些变量名称好眼熟?(。。。AAA树!。。。逃。。。
3.相当好写!压倒性优势胜过点分治有木有!
4.为了保持复杂度,询问两点距离这里采用了LCA转RMQ,做到了O(nlogn)-O(1)
#include<iostream> #include<cstdio> #include<cmath> #include<algorithm> #include<queue> #include<cstring> #define PAU putchar(' ') #define ENT putchar('\n') using namespace std; const int maxn=100000+10,maxm=200000+10,inf=-1u>>1; struct ted{int x,y,w;ted*nxt;}adj[maxm],*fch[maxn],*ms=adj; void add(int x,int y,int w){ *ms=(ted){x,y,w,fch[x]};fch[x]=ms++; *ms=(ted){y,x,w,fch[y]};fch[y]=ms++; return; } int siz[maxn],CG,size,f[maxn],dep[maxn],mi[maxm][20],Log[maxm],cnt,pos[maxn],fa[maxn]; bool vis[maxn];long long all[maxn],cha[maxn],tre[maxn]; void dfs(int x,int fa){ mi[++cnt][0]=dep[x];pos[x]=cnt;siz[x]=1; for(ted*e=fch[x];e;e=e->nxt){ int v=e->y;if(v!=fa&&!vis[v]){ dep[v]=dep[x]+e->w;dfs(v,x);siz[x]+=siz[v];mi[++cnt][0]=dep[x]; } }return; } void initrmq(){ Log[0]=-1;for(int i=1;i<=cnt;i++)Log[i]=Log[i>>1]+1; for(int j=1;(1<<j)<=cnt;j++) for(int i=1;i+(1<<j)-1<=cnt;i++) mi[i][j]=min(mi[i][j-1],mi[i+(1<<j-1)][j-1]);return; } int dist(int x,int y){ int ans=dep[x]+dep[y];x=pos[x];y=pos[y];if(x>y)swap(x,y); int k=Log[y-x+1];return ans-2*min(mi[x][k],mi[y-(1<<k)+1][k]); } void findcg(int x,int fa){ siz[x]=1;int mxs=0; for(ted*e=fch[x];e;e=e->nxt){ int v=e->y;if(v!=fa&&!vis[v]){ findcg(v,x);siz[x]+=siz[v];mxs=max(siz[v],mxs); } }f[x]=max(mxs,size-siz[x]);if(f[x]<f[CG])CG=x;return; } void solve(int x=CG){ vis[x]=true; for(ted*e=fch[x];e;e=e->nxt){ int v=e->y;if(!vis[v]){ f[CG=0]=size=siz[v];findcg(v,x);fa[CG]=x;solve(); } }return; } void update(int x,int v){ all[x]+=v; for(int ret=x;fa[x];x=fa[x]){ long long d=dist(ret,fa[x]); all[fa[x]]+=v;tre[fa[x]]+=d*v;cha[x]+=d*v; }return; } long long query(int x){ long long ans=tre[x]; for(int ret=x;fa[x];x=fa[x]){ long long d=dist(ret,fa[x]); ans+=tre[fa[x]]-cha[x]+(all[fa[x]]-all[x])*d; }return ans; } inline int read(){ int x=0,sig=1;char ch=getchar(); for(;!isdigit(ch);ch=getchar())if(ch=='-')sig=0; for(;isdigit(ch);ch=getchar())x=10*x+ch-'0'; return sig?x:-x; } inline void write(long long x){ if(x==0){putchar('0');return;}if(x<0)putchar('-'),x=-x; int len=0;long long buf[20];while(x)buf[len++]=x%10,x/=10; for(int i=len-1;i>=0;i--)putchar(buf[i]+'0');return; } int n,Q; void init(){ n=read();int x,y; for(int i=1;i<n;i++)x=read(),y=read(),add(x,y,read());dfs(1,0);initrmq(); f[CG=0]=size=n;findcg(1,0);solve(); Q=read(); while(Q--){ if(read()==2)write(query(read())),ENT; else x=read(),update(x,read()); } return; } void work(){ return; } void print(){ return; } int main(){init();work();print();return 0;} /* 7 1 5 4 1 2 5 1 3 1 3 6 2 3 4 6 4 7 2 1 6 */
相关文章推荐
- 【数据结构】 CF 547B Mike and Feet
- c++类实现二叉查找树的抽象数据结构
- 【暑假】[实用数据结构]UVa11235 Frequent values
- 【C】利用单链表数据结构实现通讯录,链表的增删改查
- 数据结构:中序线索二叉树
- Codeforces Round #303 (Div. 2) E. Paths and Trees (最短路+变形最小生成树)
- 【暑假】[实用数据结构]UVAlive 4329 Ping pong
- 数据结构基础(24) --红黑树的设计与实现(下)
- 数据结构基础(23) --红黑树的设计与实现(中)
- 数据结构基础(22)--红黑树的设计与实现(上)
- 数据结构基础(21) --DFS与BFS
- 数据结构基础(20) --图的存储结构
- 数据结构基础(19) --堆与堆排序
- Codeforces Round #Pi (Div. 2) E. President and Roads (最短路+强连通求割边)
- python数据结构学习笔记(八)
- 数据结构 单一列表
- leetcode--Two Sum II - Input array is sorted
- 数据结构之单向链表 UVa11988
- 新秀nginx源代码分析数据结构篇(四)红黑树ngx_rbtree_t
- 【暑假】[实用数据结构]UVAlive 3027 Corporative Network