题意

https://loj.ac/problem/2135

思路

首先要明确一点,答案分布是有单调性的。什么意思呢?假设我们的答案在 \(u\) 节点,\((u,v)\) 之间有一条边且 \(u\) 离答案所在的点更近,那么 \(u\) 节点作为答案一定不比在 \(v\) 节点作答案劣。从链的角度分析在拓展到树上会比较好理解这个性质。

那么如果树是一棵完全二叉树,就可以 \(\log n\) 的回答了。从根节点向下跳,每次如果找到一个 \(\displaystyle2*sum[u]\geq tot\) (\(sum[u]\) 为 \(u\) 子树点权之和, \(tot\) 为整张图点权之和)的节点,就说明存在一个更优或不劣的答案,就往这个方向跳,直到不能跳为止。更新时直接暴力修改父亲,没什么可说的。

虽然这棵树不一定是完全二叉树,但是这棵树的“分治树”高度一定是不超过 \(\log n\) 的(我个人不习惯使用“分治树”的概念,而将点分治理解为重心管辖区域这样的概念)。那么就对这棵树进行点分,存下每个数对应的每一层重心对应容器的标号,到它的距离,以及是容是斥。此题的每层重心的容器就是两个变量 \(Sum,sum\) ,其中 \(Sum\) 表示此重心管辖区域权值乘距离总和,\(sum\) 表示权值总和。那么对于 \(u\) 一层重心对应容器编号为 \(id\) ,距离 \(dis\) ,容斥系数为 \(s\) ,产生贡献即为 \(s(Sum[id]+dis\cdot sum[id])\) 。那么就能 \(O(\log n)\) 的询问取某个点的答案是多少了。

修改仍为暴力修改,没什么好说的。

关键在于回答询问,我们从整张图的重心 \(u​\) 开始跳,这个重心 \(u​\) 将树劈成了若干个连通块(题目有条件,最多 \(20​\) 个),对于其中一个连通块,我们设 \(v​\) 在这个连通块内且与 \(u​\) 有边。我们查询选 \(v​\) 的得到的答案,如果小于等于 \(u​\) 的答案,那么就要跳了。妙的是这里跳的是这个连通块的重心 \(w​\),这样就可以保证复杂度了。所以,在点分的时候就要顺便把每个层重心 \(u​\) 的下层重心 \(w​\) ,以及对应的 \(v​\) 存下来。复杂度 \(O(20 \cdot n\log ^2n)​\) ,还是挺飘的。

代码

#include<bits/stdc++.h>
#define FOR(i,x,y) for(int i=(x),i##END=(y);i<=i##END;++i)
#define DOR(i,x,y) for(int i=(x),i##END=(y);i>=i##END;--i)
using namespace std;
template<typename T,typename _T>inline bool chk_min(T &x,const _T y){return y<x?x=y,1:0;}
template<typename T,typename _T>inline bool chk_max(T &x,const _T y){return x<y?x=y,1:0;}
typedef long long ll;
const int N=1e5+5;
template<const int maxn,const int maxm>struct Linked_list
{
int head[maxn],to[maxm],nxt[maxm],cost[maxm],tot;
Linked_list(){clear();}
void clear(){memset(head,-1,sizeof(head));tot=0;}
void add(int u,int v,int w){to[++tot]=v,cost[tot]=w,nxt[tot]=head[u],head[u]=tot;}
#define EOR(i,G,u) for(int i=G.head[u];~i;i=G.nxt[i])
};
Linked_list<N,N<<1>G,H;
ll sum[N*2],Sum[N*2];int Sc;
int lv[N],Sid[N][40];ll dis[N][40];bool sgn[N][40];
int sz[N];bool mark[N];
int n,q; void CFS(int u,int f,int tot,int &C,int &Mi)
{
sz[u]=1;int res=0;
EOR(i,G,u)
{
int v=G.to[i];
if(v==f||mark[v])continue;
CFS(v,u,tot,C,Mi);
sz[u]+=sz[v];
res=max(res,sz[v]);
}
res=max(res,tot-sz[u]);
if(chk_min(Mi,res))C=u;
}
void dfs_init(int u,int f,ll D,bool s)
{
Sid[u][++lv[u]]=Sc,dis[u][lv[u]]=D,sgn[u][lv[u]]=s;
EOR(i,G,u)
{
int v=G.to[i],w=G.cost[i];
if(v==f||mark[v])continue;
dfs_init(v,u,D+w,s);
}
}
void dac(int u,int f,int tot)
{
int rt=u,Mi=1e9;
CFS(u,0,tot,u,Mi);
if(f)H.add(f,u,rt);
mark[u]=1;
Sc++,dfs_init(u,0,0,1); EOR(i,G,u)
{
int v=G.to[i],w=G.cost[i];
if(mark[v])continue;
Sc++,dfs_init(v,u,w,0);
dac(v,u,sz[u]>sz[v]?sz[v]:tot-sz[u]);
}
}
void update(int u,int val)
{
FOR(i,1,lv[u])
{
int id=Sid[u][i];ll d=dis[u][i];
sum[id]+=val;
Sum[id]+=(ll)val*d;
}
}
ll query(int u)
{
ll res=0;
FOR(i,1,lv[u])
{
int id=Sid[u][i];ll d=dis[u][i];bool s=sgn[u][i];
if(s)res+=Sum[id]+d*sum[id];
else res-=Sum[id]+d*sum[id];
}
return res;
}
ll Query(int u)
{
ll res=query(u);
EOR(i,H,u)
{
int v=H.to[i],w=H.cost[i];
if(query(w)<=res)return Query(v);
}
return res;
} int main()
{
scanf("%d%d",&n,&q);
FOR(i,1,n-1)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
G.add(u,v,w),G.add(v,u,w);
}
int C,Mi=1e9;
CFS(1,0,n,C,Mi);
memset(mark,0,sizeof(mark));
memset(lv,0,sizeof(lv));
Sc=0;
dac(1,0,n);
while(q--)
{
int u,val;
scanf("%d%d",&u,&val);
update(u,val);
printf("%lld\n",Query(C));
}
return 0;
}

ZJOI 2015 幻想乡战略游戏(动态点分治)的更多相关文章

  1. [ZJOI2015]幻想乡战略游戏——动态点分治

    [ZJOI2015]幻想乡战略游戏 带修改下,边点都带权的重心 随着变动的过程中,一些子树内的点经过会经过一些公共边.考虑能不能对这样的子树一起统计. 把树上贡献分块. 考虑点分治算法 不妨先把题目简 ...

  2. 【BZOJ3924】[Zjoi2015]幻想乡战略游戏 动态树分治

    [BZOJ3924][Zjoi2015]幻想乡战略游戏 Description 傲娇少女幽香正在玩一个非常有趣的战略类游戏,本来这个游戏的地图其实还不算太大,幽香还能管得过来,但是不知道为什么现在的网 ...

  3. 解题:ZJOI 2015 幻想乡战略游戏

    题面 神**所有点都爆int,我还以为我写出什么大锅了,不开long long见祖宗... 动态点分治利用点分树树高不超过log的性质,我们对每个点维护一个子树和,一个点分树子树和,一个点分树上父亲的 ...

  4. [BZOJ3924][ZJOI2015]幻想乡战略游戏(动态点分治)

    题目描述 傲娇少女幽香正在玩一个非常有趣的战略类游戏,本来这个游戏的地图其实还不算太大,幽香还能管得过来,但是不知道为什么现在的网游厂商把游戏的地图越做越大,以至于幽香一眼根本看不过来,更别说和别人打 ...

  5. P3345 [ZJOI2015]幻想乡战略游戏 动态点分治

    \(\color{#0066ff}{ 题目描述 }\) 傲娇少女幽香正在玩一个非常有趣的战略类游戏,本来这个游戏的地图其实还不算太大,幽香还能管得过来,但是不知道为什么现在的网游厂商把游戏的地图越做越 ...

  6. 【bzoj3924】[Zjoi2015]幻想乡战略游戏 动态点分治

    题目描述 傲娇少女幽香正在玩一个非常有趣的战略类游戏,本来这个游戏的地图其实还不算太大,幽香还能管得过来,但是不知道为什么现在的网游厂商把游戏的地图越做越大,以至于幽香一眼根本看不过来,更别说和别人打 ...

  7. ZJOI2015 幻想乡战略游戏 动态点分治_树链剖分_未调完

    Description 傲娇少女幽香正在玩一个非常有趣的战略类游戏,本来这个游戏的地图其实还不算太大,幽香还能管得过来,但是不知道为什么现在的网游厂商把游戏的地图越做越大,以至于幽香一眼根本看不过来, ...

  8. BZOJ 3924: [Zjoi2015]幻想乡战略游戏(动态点分治)

    这种动态点分治嘛,GDKOI时听打到了,也有同学讲到了,所以印象比较深刻也就想出来了,然后就在实现方面卡了好久= = 不得不说CLJ说得真的太简单了,实现方面根本没提. 首先我们可以先用树分治构建出这 ...

  9. [ZJOI2015][bzoj3924] 幻想乡战略游戏 [动态点分治]

    唉:-(动态点分治的思想真是复杂...... 先码住,再做几道题再来填坑 PS:接下来的Code因为用了倍增lca所以TLE一部分,但是懒得改成RMQ了...... Code: #include< ...

  10. loj 2135 「ZJOI2015」幻想乡战略游戏 - 动态点分治

    题目传送门 传送门 题目大意 给定一棵树,初始点权都为0,要求支持: 修改点权 询问带权重心 询问带权重心就在点分树上跑一下就行了.(枚举跳哪个子树更优) 剩下都是基础点分治. 学了一下11-dime ...

随机推荐

  1. ReactiveCocoa(III)

    flatMap(FlattenStrategy.latest) observe(on: UIScheduler()).startWithResult 切换线程: observeOn(UISchedul ...

  2. ATM取款机

    package Tests; import java.io.BufferedReader;import java.io.File;import java.io.FileInputStream;impo ...

  3. gitlab提交内容关联到slack通知

    gitlab提交内容关联到slack通知 https://docs.gitlab.com/ee/user/project/integrations/slack.html 首先去slack做相关的设置 ...

  4. subwoofer

    外文名:subwoofer 中文名:重低音音箱 俗    称:低音炮 归    类:音乐器材别    称:重低音音箱 低音炮是大家的一个俗称或者简称,严格讲应该是:重低音音箱.重低音其实是电子音乐里, ...

  5. linux 安装python3 date更新

    http://linux.51yip.com/ ntpdate -u ntp.aliyun.com   更新时间 centos 默认是有 python的,是2.7.5的 重启网络的命令  -- sys ...

  6. 算法提高 P0102

    用户输入三个字符,每个字符取值范围是0-9,A-F.然后程序会把这三个字符转化为相应的十六进制整数,并分别以十六进制,十进制,八进制输出,十六进制表示成3位,八进制表示成4位,若不够前面补0.(不考虑 ...

  7. sql语句查询结果排序

    order by 是用在where条件之后,用来对查询结果进行排序 order by 字段名 asc/desc   asc 表示升序(默认为asc,可以省略)     desc表示降序 order b ...

  8. dubbo原理

    1,观察DubboBeanDefinitionParser 的构造方法,给它打一个断点,发现其前一步在DubboNamespaceHandler 应用启动会连续调此方法 DubboBeanDefini ...

  9. linux+nginx+mysql+php环境下,安装ecshop

    我们在工作过程中要经常和电商打交道,所以,学会安装ecshop是必须的. 下面我们来介绍一下ecshop的安装. nginx和php安装整合,在我前面的文章中有提到,这里就不做赘述了.mysql可以使 ...

  10. python静态属性@property、类方法@classmethod、静态方法@staticmethod和普通方法

    静态属性:即将类的函数通过@property属性封装,封装后实例调用该函数时,不再需要在函数后面加(),而是用类似调用数据属性的方式直接调用函数名称即可执行函数. 静态属性既可以访问类的属性,也可以访 ...