zoukankan      html  css  js  c++  java
  • COJ 0970 WZJ的数据结构(负三十)树分治

    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 */
  • 相关阅读:
    单元测试课堂练习
    软件工程个人作业02
    软件工程个人作业01
    构建之法提问
    大道至简-第七、八章-心得体会
    06-接口与继承 动手动脑及验证
    大道至简-第六章-心得体会
    随机生成10个数,填充一个数组,然后用消息框显示数组内容,接着计算数组元素的和,将结果也显示在消息框中。
    大道至简-第五章-心得体会
    字符串加密
  • 原文地址:https://www.cnblogs.com/chxer/p/4712144.html
Copyright © 2011-2022 走看看