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 |
题解:先想用点分治弄离线分数:首先转化问题,转换查询和修改的对象;然后窝萌变形一下查询所求,dist(x,y)*A[x]=(dep[x]+dep[y])*A[x]=dep[x]*A[x]+dep[y]*A[x];然后窝萌就是要求出dep[x]*A[x]和A[x],这个扫两遍就好了。。。
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 #include<algorithm> 5 #include<queue> 6 #include<cstring> 7 #define PAU putchar(' ') 8 #define ENT putchar(' ') 9 using namespace std; 10 const int maxn=100000+10,maxm=200000+10,inf=-1u>>1; 11 int n,Q,A[maxn],CG,f[maxn],siz[maxn],size;bool vis[maxn]; 12 struct ted{int x,y,w;ted*nxt;}adj[maxm],*fch[maxn],*ms=adj; 13 void add(int x,int y,int w){ 14 *ms=(ted){x,y,w,fch[x]};fch[x]=ms++; 15 *ms=(ted){y,x,w,fch[y]};fch[y]=ms++; 16 return; 17 } 18 long long ans[maxn],sum,sumd,tsum,tsumd; 19 void findcg(int x,int fa){ 20 siz[x]=1;int mxs=0; 21 for(ted*e=fch[x];e;e=e->nxt){ 22 int v=e->y;if(v!=fa&&!vis[v]){ 23 findcg(v,x);siz[x]+=siz[v];mxs=max(mxs,siz[v]); 24 } 25 }f[x]=max(mxs,size-siz[x]);if(f[x]<f[CG])CG=x;return; 26 } 27 void dfs(int x,int fa,int dis){ 28 //printf("(%d,%d) ",x,dis); 29 siz[x]=1;tsum+=A[x]*dis;tsumd+=A[x];ans[x]+=dis*sumd+sum; 30 for(ted*e=fch[x];e;e=e->nxt){ 31 int v=e->y;if(v!=fa&&!vis[v]){ 32 dfs(v,x,dis+e->w);siz[x]+=siz[v]; 33 } 34 }return; 35 } 36 void solve(int x=CG){ 37 //printf("--------%d--------- ",x); 38 vis[x]=true;sum=0;sumd=A[x];static ted*s[maxm];int top=0; 39 for(ted*e=fch[x];e;e=e->nxt){ 40 s[top++]=e;int v=e->y; 41 if(!vis[v])tsum=tsumd=0,dfs(v,x,e->w),sum+=tsum,sumd+=tsumd; 42 //puts(""); 43 }ans[x]+=sum;sum=0;sumd=0; 44 while(top--){ 45 ted*e=s[top];int v=e->y;if(!vis[v])tsum=tsumd=0,dfs(v,x,e->w),sum+=tsum,sumd+=tsumd;//puts(""); 46 } 47 for(ted*e=fch[x];e;e=e->nxt){ 48 int v=e->y;if(!vis[v]){ 49 f[CG=0]=size=siz[v];findcg(v,x);solve(); 50 } 51 }return; 52 } 53 inline int read(){ 54 int x=0,sig=1;char ch=getchar(); 55 while(!isdigit(ch)){if(ch=='-')sig=-1;ch=getchar();} 56 while(isdigit(ch))x=10*x+ch-'0',ch=getchar(); 57 return x*=sig; 58 } 59 inline void write(int x){ 60 if(x==0){putchar('0');return;}if(x<0)putchar('-'),x=-x; 61 int len=0,buf[15];while(x)buf[len++]=x%10,x/=10; 62 for(int i=len-1;i>=0;i--)putchar(buf[i]+'0');return; 63 } 64 void init(){ 65 n=read();int x,y; 66 for(int i=1;i<n;i++)x=read(),y=read(),add(x,y,read()); 67 return; 68 } 69 int Qs[maxn],M; 70 void work(){ 71 Q=read();int tp,x; 72 while(Q--){ 73 tp=read();x=read(); 74 if(tp==1)A[x]+=read(); 75 else Qs[++M]=x; 76 } 77 f[CG=0]=size=n;findcg(1,0);solve(); 78 for(int i=1;i<=M;i++)printf("%lld ",ans[Qs[i]]); 79 return; 80 } 81 void print(){ 82 return; 83 } 84 int main(){init();work();print();return 0;} 85 /* 86 10 87 1 2 2 88 1 3 1 89 1 4 3 90 1 5 2 91 4 6 2 92 4 7 1 93 6 8 1 94 7 9 2 95 7 10 1 96 6 97 1 3 1 98 1 10 1 99 1 5 1 100 1 8 1 101 2 2 102 2 9 103 */
动态树做法:%%%小健健,动态树分治其实就是把重心累成一棵树,这棵树保证了树高logn。窝萌把信息分三份累加在覆盖这个操作点的最多logn个重心上,分别是整棵子树的信息all,本子树到重心的父亲的距离信息cha &#%&!。。。(意会意会。。。),本子树到重心的距离信息tre @*%&#¥%……。。。(意会意会。。。)
有几个tips!
1.窝萌的一切操作都是在重心树上进行的!
2.tre,cha,all这些变量名称好眼熟?(。。。AAA树!。。。逃。。。
3.相当好写!压倒性优势胜过点分治有木有!
4.为了保持复杂度,询问两点距离这里采用了LCA转RMQ,做到了O(nlogn)-O(1)
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 #include<algorithm> 5 #include<queue> 6 #include<cstring> 7 #define PAU putchar(' ') 8 #define ENT putchar(' ') 9 using namespace std; 10 const int maxn=100000+10,maxm=200000+10,inf=-1u>>1; 11 struct ted{int x,y,w;ted*nxt;}adj[maxm],*fch[maxn],*ms=adj; 12 void add(int x,int y,int w){ 13 *ms=(ted){x,y,w,fch[x]};fch[x]=ms++; 14 *ms=(ted){y,x,w,fch[y]};fch[y]=ms++; 15 return; 16 } 17 int siz[maxn],CG,size,f[maxn],dep[maxn],mi[maxm][20],Log[maxm],cnt,pos[maxn],fa[maxn]; 18 bool vis[maxn];long long all[maxn],cha[maxn],tre[maxn]; 19 void dfs(int x,int fa){ 20 mi[++cnt][0]=dep[x];pos[x]=cnt;siz[x]=1; 21 for(ted*e=fch[x];e;e=e->nxt){ 22 int v=e->y;if(v!=fa&&!vis[v]){ 23 dep[v]=dep[x]+e->w;dfs(v,x);siz[x]+=siz[v];mi[++cnt][0]=dep[x]; 24 } 25 }return; 26 } 27 void initrmq(){ 28 Log[0]=-1;for(int i=1;i<=cnt;i++)Log[i]=Log[i>>1]+1; 29 for(int j=1;(1<<j)<=cnt;j++) 30 for(int i=1;i+(1<<j)-1<=cnt;i++) 31 mi[i][j]=min(mi[i][j-1],mi[i+(1<<j-1)][j-1]);return; 32 } 33 int dist(int x,int y){ 34 int ans=dep[x]+dep[y];x=pos[x];y=pos[y];if(x>y)swap(x,y); 35 int k=Log[y-x+1];return ans-2*min(mi[x][k],mi[y-(1<<k)+1][k]); 36 } 37 void findcg(int x,int fa){ 38 siz[x]=1;int mxs=0; 39 for(ted*e=fch[x];e;e=e->nxt){ 40 int v=e->y;if(v!=fa&&!vis[v]){ 41 findcg(v,x);siz[x]+=siz[v];mxs=max(siz[v],mxs); 42 } 43 }f[x]=max(mxs,size-siz[x]);if(f[x]<f[CG])CG=x;return; 44 } 45 void solve(int x=CG){ 46 vis[x]=true; 47 for(ted*e=fch[x];e;e=e->nxt){ 48 int v=e->y;if(!vis[v]){ 49 f[CG=0]=size=siz[v];findcg(v,x);fa[CG]=x;solve(); 50 } 51 }return; 52 } 53 void update(int x,int v){ 54 all[x]+=v; 55 for(int ret=x;fa[x];x=fa[x]){ 56 long long d=dist(ret,fa[x]); 57 all[fa[x]]+=v;tre[fa[x]]+=d*v;cha[x]+=d*v; 58 }return; 59 } 60 long long query(int x){ 61 long long ans=tre[x]; 62 for(int ret=x;fa[x];x=fa[x]){ 63 long long d=dist(ret,fa[x]); 64 ans+=tre[fa[x]]-cha[x]+(all[fa[x]]-all[x])*d; 65 }return ans; 66 } 67 inline int read(){ 68 int x=0,sig=1;char ch=getchar(); 69 for(;!isdigit(ch);ch=getchar())if(ch=='-')sig=0; 70 for(;isdigit(ch);ch=getchar())x=10*x+ch-'0'; 71 return sig?x:-x; 72 } 73 inline void write(long long x){ 74 if(x==0){putchar('0');return;}if(x<0)putchar('-'),x=-x; 75 int len=0;long long buf[20];while(x)buf[len++]=x%10,x/=10; 76 for(int i=len-1;i>=0;i--)putchar(buf[i]+'0');return; 77 } 78 int n,Q; 79 void init(){ 80 n=read();int x,y; 81 for(int i=1;i<n;i++)x=read(),y=read(),add(x,y,read());dfs(1,0);initrmq(); 82 f[CG=0]=size=n;findcg(1,0);solve(); 83 Q=read(); 84 while(Q--){ 85 if(read()==2)write(query(read())),ENT; 86 else x=read(),update(x,read()); 87 } 88 return; 89 } 90 void work(){ 91 return; 92 } 93 void print(){ 94 return; 95 } 96 int main(){init();work();print();return 0;} 97 /* 98 7 99 1 5 4 100 1 2 5 101 1 3 1 102 3 6 2 103 3 4 6 104 4 7 2 105 1 6 106 */