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(‘\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 */
时间: 2024-12-19 21:03:08

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

COJ966 WZJ的数据结构(负三十四)

WZJ的数据结构(负三十四) 难度级别:C: 运行时间限制:20000ms: 运行空间限制:262144KB: 代码长度限制:2000000B 试题描述 给一棵n个节点的树,请对于形如"u r"的Q个询问, 回答以 u 节点为中心,半径 r 以内的节点中,权值最大的节点的编号是多少.如果有多个节点,返回编号最小的. 输入 共有一组测试数据.第一行包含一个整数 n (1 ≤ n ≤ 10^5),表示节点总数.接下来的一行,包含 n 个数字,表示每个节点的权值 vi (1 ≤ vi ≤ 1

COJ968 WZJ的数据结构(负三十二)

WZJ的数据结构(负三十二) 难度级别:D: 运行时间限制:5000ms: 运行空间限制:262144KB: 代码长度限制:2000000B 试题描述 给你一棵N个点的无根树,边上均有权值,每个点上有一盏灯,初始均亮着.请你设计一个数据结构,回答M次操作. 1 x:将节点x上的灯拉一次,即亮变灭,灭变亮. 2 x k:询问当前所有亮灯的节点中距离x第k小的距离(注意如果x亮着也算入). 输入 第一行为一个正整数N.第二行到第N行每行三个正整数ui,vi,wi.表示一条树边从ui到vi,距离为wi

COJ970 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.最后

COJ 0981 WZJ的数据结构(负十九)树综合

WZJ的数据结构(负十九) 难度级别:E: 运行时间限制:15000ms: 运行空间限制:262144KB: 代码长度限制:2000000B 试题描述 WZJ的数据结构中有很多都是关于树的.这让很多练习模板的同学还要找来找去很不爽,于是WZJ跟小伙伴们一块商量如何将这些题汇拢到一块去: WZJ:为了大家简单,我规定一开始是一棵有根树. LZJ:那我一定得加上换根操作喽. XJR:链信息修改,链信息增加,链信息翻倍,维护链信息的最大,最小,总和肯定很好做. CHX:子树信息修改,子树信息增加,子树

COJ 0967 WZJ的数据结构(负三十三)

WZJ的数据结构(负三十三) 难度级别:E: 运行时间限制:7000ms: 运行空间限制:262144KB: 代码长度限制:2000000B 试题描述 请你设计一个数据结构,完成以下功能: 给定一个大小为N的整数组A,要求你回答执行N次操作.操作分两种: 操作1:每次操作给你l,r,v三个参数,求Al至Ar中值<=v的个数. 操作2:每次操作给你l,r,v三个参数,将Al至Ar所有数的值设为v. 输入 第一行为一个正整数N.第二行为N个整数Ai.接下来N行每行4个正整数t,l,r,v.若t=2表

COJ 0979 WZJ的数据结构(负二十一)

WZJ的数据结构(负二十一) 难度级别:C: 运行时间限制:5000ms: 运行空间限制:262144KB: 代码长度限制:2000000B 试题描述 请你实现一个数据结构,完成这样的功能: 给你一个N个点的图,初始状态无边. 每次加入一条双向边(u,v,w),若加入后没有构成一棵生成树,输出“Not Yet”,否则输出当前最小生成树的权值. 输入 第一行两个正整数N,M.表示有N个点M个操作.接下来M行每行三个正整数u,v,w. 输出 每次加入一条双向边(u,v,w),若加入后没有构成一棵生成

COJ 0995 WZJ的数据结构(负五)区间操作

WZJ的数据结构(负五) 难度级别:C: 运行时间限制:1000ms: 运行空间限制:262144KB: 代码长度限制:2000000B 试题描述 请你设计一个数据结构,完成以下功能: 给定一个大小为N的整数组A,要求你回答执行M次操作.操作分两种: 操作1:每次操作给你l,r,v三个参数,求Al至Ar中值<=v的个数. 操作2:每次操作给你l,r,v三个参数,将Al至Ar中每个数的值+v. 输入 第一行为一个正整数N.第二行为N个整数Ai.第三行为一个正整数M.接下来M行每行4个正整数t,l,

COJ 1010 WZJ的数据结构(十) 线段树区间操作

传送门:http://oj.cnuschool.org.cn/oj/home/problem.htm?problemID=1001 WZJ的数据结构(十) 难度级别:D: 运行时间限制:3000ms: 运行空间限制:51200KB: 代码长度限制:2000000B 试题描述 请你设计一个数据结构,高效执行以下过程: #include<iostream>using namespace std;const int maxn=100010;int A[maxn];int tp,ql,qr,v;int

COJ 0999 WZJ的数据结构(负一)

WZJ的数据结构(负一) 难度级别:D: 运行时间限制:1000ms: 运行空间限制:262144KB: 代码长度限制:2000000B 试题描述 输入N个模板串Pi和文本串T,输出每个模板串Pi在T中出现了多少次. 输入 第一行为一个正整数N.接下来N行为Pi.最后一行为T 输出 输出N行,第i行为模板串Pi在T中出现的次数. 输入示例 5aabbaabaaababababa 输出示例 54445 其他说明 1<=sigma(|Pi|)<=10000001<=|T|<=10000