码迷,mamicode.com
首页 > 其他好文 > 详细

COJ 0970 WZJ的数据结构(负三十)树分治

时间:2015-08-07 23:43:14      阅读:189      评论:0      收藏:0      [点我收藏+]

标签:

 

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(‘\n‘)
  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---------\n",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\n",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(‘\n‘)
  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 */

 

COJ 0970 WZJ的数据结构(负三十)树分治

标签:

原文地址:http://www.cnblogs.com/chxer/p/4712144.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!