前言

略略略

题目相关

链接

题目大意

给出一棵树,每次修改一个点的权值,维护一个带权重心
啥是带权重心?
设点iii的值为ViV_iVi​我们要选一个点uuu,每个点对应一个值:
∑v=1nVv∗dis(u,v)\sum_{v=1}^n V_v*dis(u,v)v=1∑n​Vv​∗dis(u,v)
我们要选一个uuu使得这个值最小
输出最小的值

数据范围

n,q≤105n,q\le10^5n,q≤105,每个点的度数不多于20,时限6s

题解

动态点分治(点分树)
很久之前学了点分树,但一直都没做什么题
我们考虑这样一件事
假如我们现在选了一个点uuu,那么只有它向带权重心的方向vvv移动时答案才会变优(证明很显然,带权重心方向的点权和比另外一边的点权大,这样的话e*点权只差就是正的)
我们考虑最裸的情况,每次修改后,我们从根节点开始,如果其往某个子树移动答案会变优(设sizeisize_isizei​为iii的子树大小,那么这个条件是eu,v∗(sizeu−sizev−sizev&lt;0e_{u,v}*(size_u-size_v-size_v&lt;0eu,v​∗(sizeu​−sizev​−sizev​<0,容易发现这样的儿子对多只有一个),那么说明带权重心在那个子树中,那就把当前答案往那个子树移
我们发现这个复杂度可以被卡到O(n2)\mathcal O(n^2)O(n2),因为往儿子走可能会走很多次

考虑点分治之后建出点分树,我们在跳子树的时候跳到那个子树的重心(注意与带权重心区分)即可,容易发现,由于点分树树高logn,所以这个跳子树的操作使得复杂度变为O(nlogn)\mathcal O(nlogn)O(nlogn)

现在要快速维护每个点的答案(当然是推过来而不是直接求)
我们维护每个分治子树权值和sizeusize_usizeu​(uuu为分治重心),每个分治子树到重心的贡献值gug_ugu​,每个节点子树到该子树的lca的父亲的贡献值fuf_ufu​
怎么维护呢?即对于一次修改怎么维护答案
我们发现,直接跳点分树即可,用O(1)\mathcal O(1)O(1)求距离的话,单次修改的复杂度是O(logn)\mathcal O(logn)O(logn)的
再维护一个全局点权和SIZESIZESIZE
我们现在相当于对于当前答案的每条出边,并且询问这条边划分出的子树sizesizesize是否大于全局的一半,如果是就走过去,直到找到答案点,最终计算答案
我们发现子树size和答案并不好维护
考虑记录历史走过的每一个点分重心,这样我们可以做到单次lognlognlogn的询问
我们发现一个点的度数总共只有202020个,直接枚举出边即可

综上,复杂度O(20nlog2n)\mathcal O(20nlog^2n)O(20nlog2n)
不是很满,但是复杂度感觉挺高的

代码

#include<cstdio>
#include<cctype>
#include<algorithm>
#include<vector>
namespace fast_IO
{const int IN_LEN=1000000,OUT_LEN=1000000;char ibuf[IN_LEN],obuf[OUT_LEN],*ih=ibuf+IN_LEN,*oh=obuf,*lastin=ibuf+IN_LEN,*lastout=obuf+OUT_LEN-1;inline char getchar_(){return (ih==lastin)&&(lastin=(ih=ibuf)+fread(ibuf,1,IN_LEN,stdin),ih==lastin)?EOF:*ih++;}inline void putchar_(const char x){if(oh==lastout)fwrite(obuf,1,oh-obuf,stdout),oh=obuf;*oh++=x;}inline void flush(){fwrite(obuf,1,oh-obuf,stdout);}
}
using namespace fast_IO;
#define getchar() getchar_()
#define putchar(x) putchar_((x))
#define rg register
typedef long long ll;
template <typename T> inline T max(const T a,const T b){return a>b?a:b;}
template <typename T> inline T min(const T a,const T b){return a<b?a:b;}
template <typename T> inline void mind(T&a,const T b){a=a<b?a:b;}
template <typename T> inline void maxd(T&a,const T b){a=a>b?a:b;}
template <typename T> inline T abs(const T a){return a>0?a:-a;}
template <typename T> inline void Swap(T&a,T&b){T c=a;a=b;b=c;}
template <typename T> inline T gcd(const T a,const T b){if(!b)return a;return gcd(b,a%b);}
template <typename T> inline T lcm(const T a,const T b){return a/gcd(a,b)*b;}
template <typename T> inline T square(const T x){return x*x;};
template <typename T> inline void read(T&x)
{char cu=getchar();x=0;bool fla=0;while(!isdigit(cu)){if(cu=='-')fla=1;cu=getchar();}while(isdigit(cu))x=x*10+cu-'0',cu=getchar();if(fla)x=-x;
}
template <typename T> inline void printe(const T x)
{if(x>=10)printe(x/10);putchar(x%10+'0');
}
template <typename T> inline void print(const T x)
{if(x<0)putchar('-'),printe(-x);else printe(x);
}
const int maxn=100001,maxm=200001;
int n,Q;
int head[maxn],nxt[maxm],tow[maxm],vau[maxm],tmp;
inline void addb(const int u,const int v,const int w)
{tmp++;nxt[tmp]=head[u];head[u]=tmp;tow[tmp]=v;vau[tmp]=w;
}
int minn,root,SIZE,son[maxn];
bool vis[maxn];
void getroot(const int u,const int fa)
{son[u]=1;int maxx=0;for(rg int i=head[u];i;i=nxt[i]){const int v=tow[i];if(v!=fa&&!vis[v]){getroot(v,u);son[u]+=son[v];maxd(maxx,son[v]);}}maxd(maxx,SIZE-son[u]);if(maxx<minn)minn=maxx,root=u;
}
int ROOT,F[maxn];
std::vector<int>E[maxn];
int fr[maxn];
void solve(const int u,const int SZ,const int SON)
{vis[u]=1;for(rg int i=head[u];i;i=nxt[i]){const int v=tow[i];if(!vis[v]){minn=0x7fffffff,SIZE=son[v];if(SIZE>SON)SIZE=SZ-SON;getroot(v,u);E[u].push_back(root);F[root]=u,fr[root]=v;solve(root,SIZE,son[root]);}}
}
int rmq[maxm][21],top,fst[maxn];
ll dep[maxn];
void dfs(const int u,const int fa)
{rmq[++top][0]=u;fst[u]=top;for(rg int i=head[u];i;i=nxt[i]){const int v=tow[i];if(v!=fa)dep[v]=dep[u]+vau[i],dfs(v,u),rmq[++top][0]=u;}
}
int bit[21],log_[3000000];
int MIN(const int u,const int v){return dep[u]<dep[v]?u:v;}
int lca(const int u,const int v)
{const int A=min(fst[u],fst[v]),B=max(fst[u],fst[v]);return MIN(rmq[A][log_[B-A+1]],rmq[B-bit[log_[B-A+1]]+1][log_[B-A+1]]);
}
ll dis(const int u,const int v)
{return dep[u]+dep[v]-(dep[lca(u,v)]<<1);
}
ll g[maxn],f[maxn],size[maxn];
ll vvv[maxn];
int stack[21],tot;ll sz[21];
ll calc(const int l,const int r)
{ll res=0;for(rg int i=1;i<=tot;i++)if(dis(stack[i],l)>dis(stack[i],r))res+=sz[i];return res;
}
ll Res(const int p)
{ll res=g[p];stack[++tot]=p;for(rg int i=1;i<tot;i++)res+=g[stack[i]]-f[stack[i+1]]+(size[stack[i]]-size[stack[i+1]])*dis(stack[i],p);return res;
}
int main()
{bit[0]=1;for(rg int i=1;i<=20;i++)bit[i]=bit[i-1]<<1;for(rg int i=1;i<=20;i++)for(rg int j=bit[i];j<(bit[i]<<1);j++)log_[j]=i;read(n),read(Q);for(rg int i=1;i<n;i++){int u,v,w;read(u),read(v),read(w);addb(u,v,w),addb(v,u,w);}minn=0x7fffffff,SIZE=n,getroot(1,1);ROOT=root;solve(root,SIZE,son[root]);dfs(1,1);for(rg int i=1;i<=20;i++)for(rg int j=1;j+bit[i]-1<=top;j++)rmq[j][i]=MIN(rmq[j][i-1],rmq[j+bit[i-1]][i-1]);SIZE=0;for(rg int i=1;i<=Q;i++){int p,O,more;read(p),O=p,read(more),vvv[p]+=more;size[p]+=more,SIZE+=more;while(p!=ROOT){const ll R=dis(O,F[p]);f[p]+=R*more,g[F[p]]+=R*more;p=F[p];size[p]+=more;}p=ROOT;tot=0;while(1){bool fla=1;for(unsigned int j=0;j<E[p].size();j++){const int v=E[p][j];const ll SZ=calc(p,fr[v])+size[v];if(SZ*2>SIZE){fla=0;stack[++tot]=p,sz[tot]=size[p]-size[v];p=v;break;}}if(fla)break;}print(Res(p)),putchar('\n');}return flush(),0;
}

总结

对点分树的理解程度++
感觉自己还是做题太少了

[zjoi2015]幻想乡战略游戏相关推荐

  1. P3345 [ZJOI2015]幻想乡战略游戏

    P3345 [ZJOI2015]幻想乡战略游戏 带修改带权重心 这是经典的树上寻找关键点的题目,我们使用点分治处理这个问题,因为点分治的特性,就相当于在树上二分了.但是这与倍增不同,倍增只是在链上二分 ...

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

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

  3. [ZJOI2015] 幻想乡战略游戏——树链剖分

    [ZJOI2015]幻想乡战略游戏 题解 由于所有边的边权是正整数,所以可以发现任何时刻每个点的答案是从最优的点往周围递增的.如果有平台,那么一定是在最优点的连通块那儿. 我们先考虑如何快速求每个点的 ...

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

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

  5. Bzoj3924 [Zjoi2015]幻想乡战略游戏

    Time Limit: 100 Sec  Memory Limit: 256 MB Submit: 817  Solved: 376 Description 傲娇少女幽香正在玩一个非常有趣的战略类游戏 ...

  6. luogu_P3345[zjoi2015]幻想乡战略游戏

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

  7. BZOJ3924 : [Zjoi2015]幻想乡战略游戏

    对于一个点,要求出它到所有点的带权距离和,只需记录下树分治的结构然后查询即可. 修改$O(\log n)$,查询$O(\log n)$. 到所有点带权距离和最小的点显然是这棵树的带权重心. 以1号点为 ...

  8. [ZJOI2015] 幻想乡战略游戏(树链剖分 + 线段树二分 + 带权重心)

    problem luogu-P3345 solution 这是一个带权重心的题,考察动态点分治.点分治?呵,不可能的,这辈子都不可能写点分治 我们重新考虑重心的性质:以这个点为根时,所有子树的大小不会 ...

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

    二刷这题 在树上寻找带点权和边权的重心,考虑在原树上怎么做: 假设当前答案在根节点 uuu,考虑移动到子节点 vvv,贡献变化是 wu,v∗(tot−2sumv)w_{u,v} * (tot - 2s ...

最新文章

  1. AI顶级会议以及期刊
  2. SVN如何将版本库url访问地址中的https改为http
  3. 基于深度学习的语义分割代码库
  4. 网页登录接口php,thinkphp-登入接口示例
  5. Ubuntu 16.04 安装第三方Apps Can’t Install Third-Party Apps on Ubuntu 16.04? You’re No
  6. excel相乘再相加_简单的工作花几小时,学会几个Excel技巧,几秒钟解决
  7. hive 操作(三)——hive 的数据模型
  8. @Resource 注解和 @Autowired 注解的对比
  9. ai人工智能可以干什么_我们可以使人工智能更具道德性吗?
  10. 本地图片的预览和上传
  11. 法拉科机器人编程软件_发那科 FANUC 机器人仿真软件 中文 roboguide9.1 视频教程...
  12. NetCore mysql Connection open error . The given key ‘25971‘ was not present in the dictionary
  13. 简单的图片数字时钟js代码
  14. 别让失败阻碍了你成功的路
  15. 易读文库桌面版1.2预览
  16. Linux上杀毒软件有哪些?
  17. Codeforces Round #694 (Div. 1) 部分简要题解
  18. PHP json_encode float
  19. 天敏VC4000视频开发设计方案
  20. 蓝牙+语音系列产品分类

热门文章

  1. ActiveMQ入门-ActiveMQ跟SpringBoot整合发送接收Topic
  2. MapReduce-流量统计求和-步骤分析
  3. RocketMQ的Consumer详解之push和pull模式(长轮询)
  4. Filter_细节_执行流程生命周期
  5. spring事务管理-演示事务的环境准备
  6. java 读取 excel poi_java poi怎么获取excel单元格的内容?
  7. ebs java并发_EBS中Java并发程序笔记(1)
  8. python自动化测试脚本后端_基于 python 的接口自动化测试
  9. java版spring cloud+spring boot+redis多租户社交电子商务平台(三)SpringBoot用JdbcTemplates访问Mysql...
  10. 一段话系列-领域模型是什么?