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],这个扫两遍就好了。。。
#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=+,maxm=+,inf=-1u>>;
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]=;int mxs=;
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]=;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=;sumd=A[x];static ted*s[maxm];int top=;
for(ted*e=fch[x];e;e=e->nxt){
s[top++]=e;int v=e->y;
if(!vis[v])tsum=tsumd=,dfs(v,x,e->w),sum+=tsum,sumd+=tsumd;
//puts("");
}ans[x]+=sum;sum=;sumd=;
while(top--){
ted*e=s[top];int v=e->y;if(!vis[v])tsum=tsumd=,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=]=size=siz[v];findcg(v,x);solve();
}
}return;
}
inline int read(){
int x=,sig=;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')sig=-;ch=getchar();}
while(isdigit(ch))x=*x+ch-'',ch=getchar();
return x*=sig;
}
inline void write(int x){
if(x==){putchar('');return;}if(x<)putchar('-'),x=-x;
int len=,buf[];while(x)buf[len++]=x%,x/=;
for(int i=len-;i>=;i--)putchar(buf[i]+'');return;
}
void init(){
n=read();int x,y;
for(int i=;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==)A[x]+=read();
else Qs[++M]=x;
}
f[CG=]=size=n;findcg(,);solve();
for(int i=;i<=M;i++)printf("%lld\n",ans[Qs[i]]);
return;
}
void print(){
return;
}
int main(){init();work();print();return ;}
/*
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=+,maxm=+,inf=-1u>>;
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][],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][]=dep[x];pos[x]=cnt;siz[x]=;
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][]=dep[x];
}
}return;
}
void initrmq(){
Log[]=-;for(int i=;i<=cnt;i++)Log[i]=Log[i>>]+;
for(int j=;(<<j)<=cnt;j++)
for(int i=;i+(<<j)-<=cnt;i++)
mi[i][j]=min(mi[i][j-],mi[i+(<<j-)][j-]);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+];return ans-*min(mi[x][k],mi[y-(<<k)+][k]);
}
void findcg(int x,int fa){
siz[x]=;int mxs=;
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=]=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=,sig=;char ch=getchar();
for(;!isdigit(ch);ch=getchar())if(ch=='-')sig=;
for(;isdigit(ch);ch=getchar())x=*x+ch-'';
return sig?x:-x;
}
inline void write(long long x){
if(x==){putchar('');return;}if(x<)putchar('-'),x=-x;
int len=;long long buf[];while(x)buf[len++]=x%,x/=;
for(int i=len-;i>=;i--)putchar(buf[i]+'');return;
}
int n,Q;
void init(){
n=read();int x,y;
for(int i=;i<n;i++)x=read(),y=read(),add(x,y,read());dfs(,);initrmq();
f[CG=]=size=n;findcg(,);solve();
Q=read();
while(Q--){
if(read()==)write(query(read())),ENT;
else x=read(),update(x,read());
}
return;
}
void work(){
return;
}
void print(){
return;
}
int main(){init();work();print();return ;}
/*
7
1 5 4
1 2 5
1 3 1
3 6 2
3 4 6
4 7 2
1 6
*/
COJ 0970 WZJ的数据结构(负三十)树分治的更多相关文章
- COJ 1003 WZJ的数据结构(三)ST表
WZJ的数据结构(三) 难度级别:B: 运行时间限制:3000ms: 运行空间限制:51200KB: 代码长度限制:2000000B 试题描述 请你设计一个数据结构,完成以下功能: 给定一个大小为N的 ...
- COJ966 WZJ的数据结构(负三十四)
WZJ的数据结构(负三十四) 难度级别:C: 运行时间限制:20000ms: 运行空间限制:262144KB: 代码长度限制:2000000B 试题描述 给一棵n个节点的树,请对于形如"u ...
- COJ970 WZJ的数据结构(负三十)
WZJ的数据结构(负三十) 难度级别:D: 运行时间限制:1000ms: 运行空间限制:262144KB: 代码长度限制:2000000B 试题描述 给你一棵N个点的无根树,点和边上均有权值.请你设计 ...
- COJ968 WZJ的数据结构(负三十二)
WZJ的数据结构(负三十二) 难度级别:D: 运行时间限制:5000ms: 运行空间限制:262144KB: 代码长度限制:2000000B 试题描述 给你一棵N个点的无根树,边上均有权值,每个点上有 ...
- [COJ0968]WZJ的数据结构(负三十二)
[COJ0968]WZJ的数据结构(负三十二) 试题描述 给你一棵N个点的无根树,边上均有权值,每个点上有一盏灯,初始均亮着.请你设计一个数据结构,回答M次操作. 1 x:将节点x上的灯拉一次,即亮变 ...
- [COJ0970]WZJ的数据结构(负三十)
[COJ0970]WZJ的数据结构(负三十) 试题描述 给你一棵N个点的无根树,点和边上均有权值.请你设计一个数据结构,回答M次操作. 1 x v:对于树上的每一个节点y,如果将x.y在树上的距离记为 ...
- COJ 0967 WZJ的数据结构(负三十三)
WZJ的数据结构(负三十三) 难度级别:E: 运行时间限制:7000ms: 运行空间限制:262144KB: 代码长度限制:2000000B 试题描述 请你设计一个数据结构,完成以下功能: 给定一个大 ...
- COJ 0990 WZJ的数据结构(负十)
WZJ的数据结构(负十) 难度级别:D: 运行时间限制:5000ms: 运行空间限制:51200KB: 代码长度限制:2000000B 试题描述 给你一个N个节点的有根树,从1到N编号,根节点为1并给 ...
- COJ 0981 WZJ的数据结构(负十九)树综合
WZJ的数据结构(负十九) 难度级别:E: 运行时间限制:3500ms: 运行空间限制:262144KB: 代码长度限制:2000000B 试题描述 WZJ的数据结构中有很多都是关于树的.这让很多练习 ...
随机推荐
- ZYKeyboardUtil 全自动处理键盘遮挡事件
键盘遮盖输入控件或按钮在日常app开发中避之不及,考虑各种情况下UI各种嵌套,最后还要注册监听再获取指定键盘信息.我们可以通过键盘处理工具类ZYKeyboardUtil避繁就简,利用Block的方式处 ...
- mac 终端常见指令
基本命令 1.列出文件 ls 参数 目录名 例: 看看驱动目录下有什么:ls /System/Library/Extensions参数 -w 显示中文,-l 详细信息, -a 包括隐藏文 ...
- 重载,重写和super
1.重载的概念:----->在同一个类中,允许存在同名函数,但它们的参数个数或者参数类型不同即可.public static void main(String[] args){System.ou ...
- LTP 分词算法实践
参考链接: https://github.com/HIT-SCIR/ltp/blob/master/doc/install.rst http://www.xfyun.cn/index.php/serv ...
- HTML5媒体播放说明
HTML5中video标签播放m3u8整理 http://www.xue163.com/588880/39097/390970871.html 移动端HTML5<video>视频播放优化实 ...
- Android开发中用友盟做分享的一些坑
仅限于用5.1.4版本的 按照友盟分享的API在自己的代码中修改: 1.微信分享需要打包APK文件,数字签名与微信开发申请的要一致 2.此name中属性不能修改 value为友盟的申请的appkey ...
- iOS中JavaScript和OC交互
转载自:http://www.devzeng.com/blog/ios-uiwebview-interaction-with-javascript.html 还可参考的文章:http://blog.c ...
- Wpf自定义路由事件
创建自定义路由事件大体可以分为三个步骤: ①声明并注册路由事件. ②为路由事件添加CLR事件包装. ③创建可以激发路由事件的方法. 以ButtonBase类中代码为例展示这3个步骤: public a ...
- 谢尔排序/缩减增量排序(C++)
谢尔排序/缩减增量排序(C++) 谢尔排序/缩减增量排序: 他通过比较相距一定间隔的元素来工作,各趟比较所用的距离随着算法的进行而减小,直到只比较相邻元素的最后一趟排序为止.(好复杂) 看了一下实现代 ...
- 371. Sum of Two Integers -- Avota
问题描述: Calculate the sum of two integers a and b, but you are not allowed to use the operator + and - ...