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的数据结构中有很多都是关于树的.这让很多练习 ...
随机推荐
- 【网络通信】服务器端Socket监听80端口,建立连接传输数据时也是使用的80端口么?
1. 服务器端Socket监听80端口,建立连接传输数据时也是使用的80端口么? 答:对.建立连接时服务器会分配一个新的Socket,但是用的源端口号还是80端口.套接字是由协议类型.源IP.目的IP ...
- 一次优化web项目的经历记录(二)
一次优化web项目的经历记录 这段时间以来的总结与反思 前言:最近很长一段时间没有更新博客了,忙于一堆子项目的开发,严重拖慢了学习与思考的进程. 开水倒满了需要提早放下杯子,晚了就会烫手,这段时间以来 ...
- 开始android博客分享
现在开始写博客,分享android开发中的心得.
- Python开发【第二十篇】:缓存
Python开发[第二十篇]:缓存redis&Memcache 点击这里 Python之路[第九篇]:Python操作 RabbitMQ.Redis.Memcache.SQLAlchemy ...
- 10.4 noip模拟试题
题目名称 PA 青春 三部曲 名称 huakai taritari truetears 输入 huakai.in taritari.in truetears.in 输出 huakai.out tari ...
- 点击文字可以选中相应的checkbox
<html><head><title>中国站长天空-网页特效-表单特效-点击文字选中的复选框</title><meta http-equiv=&q ...
- powerdesigner设置唯一键,但不是主键的方式
[转载]http://blog.csdn.net/cnham/article/details/6676650 唯一约束 唯一约束与创建唯一索引基本上是一回事,因为在创建唯一约束的时候,系统会创建对应的 ...
- oracle触发器调试
1.如下图位置点击触发器,会出现调试窗口 2.执行编译并调试 3.点击小虫,将画红位置,加入会触发此触发器的语句.如果触发器执行成功,不会出现第4个图,不成功,会出现数据调试信息,具体报错位置会定位到 ...
- Singleton设计模式的一种见解
单实例Singleton设计模式可能是被讨论和使用的最广泛的一个设计模式了,这可能也是面试中问得最多的一个设计模式了.这个设计模式主要目的是想在整个系统中只能出现一个类的实例.这样做当然是有必然的,比 ...
- TOM大师脚本01-查找未建索引的外键
[oracle@Oracle11g 2016]$ cat 022201.sql column columns format a30 word_wrappedcolumn tablename forma ...