bzoj 3924 点分
感谢asm.Definer清楚明了的题解:
http://www.cnblogs.com/Asm-Definer/p/4470112.html
收获:
1. 关于重心, 对于一个无向图, 我们这样给每条边重新确定方向: u<->v这条边将原图分成两个部分Su,Sv,w(S)表示S集合中点的权值和,那么
u->v 当 w(Su)<w(Sv)
u<-v 当 w(Su)>w(Sv)
u<->v 当 w(Su)=w(Sv)
那么从一个点沿着边的方向走,直到走到一个区域,使得走不出这个区域,那么这个区域中的任何一个点就是重心.
2. 有了第一条,就可以运用点分来搞一些询问某个点的的东西了(这里就是询问以这个点为重心的权和).
再用点分最多log层和类似1的性质,就可以做了.
3. 点分不擅长求全局最...的东西,而是擅长关于某个点....的东西.
这道题可以用是因为有重心位置的单调性.
还有捉迷藏那道题是用堆来辅助的.
#include <cstdio>
#include <vector>
#include <map>
#define max(a,b) ((a)>(b)?(a):(b))
#define oo 0x3f3f3f3f3f3f3f3fLL
#define N 100010
#define M N<<1
#define P 17
using namespace std; typedef long long dnt;
struct Info {
int p, s;
Info(){}
Info( int p, int s ):p(p),s(s){}
};
struct Pair {
int s, c;
Pair(){}
Pair( int s, int c ):s(s),c(c){}
}; int n, m;
int head[N], dest[M], wght[M], next[M], etot;
int idv[M], vid[N], dep[N], stu[M][P+], stp[M][P+];
int bac[N], fat[N], siz[N], vis[N], dis[N];
int bin[P+], log[M], qu[N], bg, ed;
//Info info[N][P+1]; int icnt[N];
//Pair gc[N][22]; int gcnt[N];
vector<Info> info[N];
vector<Pair> gc[N];
dnt cans[N], fans[N], sumw[N];
dnt rans[N]; int tag[N], curt; inline void uMax( int &u, int v ) { if( u<v ) u=v; }
void adde( int u, int v, int w ) {
etot++;
dest[etot] = v;
wght[etot] = w;
next[etot] = head[u];
head[u] = etot;
}
void build_lca( int s ) {
// qu fat dep dis, siz
fat[s] = ;
dep[s] = ;
dis[s] = ;
siz[s] = ;
qu[bg=ed=] = s;
while( bg<=ed ) {
int u=qu[bg++];
for( int t=head[u]; t; t=next[t] ) {
int v=dest[t], w=wght[t];
if( v==fat[u] ) continue;
fat[v] = u;
siz[v] = ;
dep[v] = dep[u]+;
dis[v] = dis[u]+w;
qu[++ed] = v;
}
}
// siz
for( register int i=ed; i>=; i-- ) {
int u=qu[i], p=fat[u];
siz[u]++;
siz[p]+=siz[u];
}
siz[s]++;
// idv vid
vid[s] = ;
idv[] = s;
for( register int i=; i<=ed; i++ ) {
int u=qu[i];
int cur=vid[u]+;
for( register int t=head[u]; t; t=next[t] ) {
int v=dest[t];
if( v==fat[u] ) continue;
idv[cur] = u;
cur++;
vid[v] = cur;
idv[cur] = v;
cur += siz[v]+siz[v]-;
}
}
idv[n+n] = s;
// bin log
int idc = n+n;
bin[] = ;
for( int i=; i<=P; i++ ) bin[i] = bin[i-]<<;
log[] = -;
for( int i=; i<=idc; i++ ) log[i] = log[i>>]+;
// stu stp
for( int i=; i<=idc; i++ ) {
stu[i][] = idv[i];
stp[i][] = dep[idv[i]];
}
for( int p=; p<=log[idc]; p++ ) {
for( register int i=; i<=idc-bin[p]+; i++ ) {
if( stp[i][p-] < stp[i+bin[p-]][p-] ) {
stp[i][p] = stp[i][p-];
stu[i][p] = stu[i][p-];
} else {
stp[i][p] = stp[i+bin[p-]][p-];
stu[i][p] = stu[i+bin[p-]][p-];
}
}
}
}
inline int lca( int u, int v ) {
int lf=vid[u], rg=vid[v];
if( lf>rg ) swap(lf,rg);
int p = log[rg-lf+];
if( stp[lf][p] < stp[rg-bin[p]+][p] )
return stu[lf][p];
else
return stu[rg-bin[p]+][p];
}
inline int qu_dis( int u, int v ) {
int ca = lca(u,v);
return dis[u]+dis[v]-(dis[ca]<<);
}
int build_vdcp( int s ) {
int c;
// qu fat, siz bac
fat[s] = ;
siz[s] = bac[s] = ;
qu[bg=ed=] = s;
while( bg<=ed ) {
int u=qu[bg++];
for( int t=head[u]; t; t=next[t] ) {
int v=dest[t];
if( v==fat[u] || vis[v] ) continue;
fat[v] = u;
siz[v] = bac[v] = ;
qu[++ed] = v;
}
}
// siz bac
for( register int i=ed; i>=; i-- ) {
int u=qu[i], p=fat[u];
siz[u]++;
siz[p]+=siz[u];
uMax( bac[p], siz[u] );
}
siz[s]++;
// bac c
c = ;
for( register int i=; i<=ed; i++ ) {
int u=qu[i];
uMax( bac[u], siz[s]-siz[u] );
if( bac[u]<bac[c] ) c=u;
}
// qu info
vis[c] = true;
vector<int> stk;
for( int t=head[c]; t; t=next[t] ) {
int s=dest[t], cc;
if( vis[s] ) continue; qu[bg=ed=] = s;
fat[s] = c;
stk.clear();
while( bg<=ed ) {
int u=qu[bg++];
stk.push_back( u );
for( int t=head[u]; t; t=next[t] ) {
int v=dest[t];
if( v==fat[u] || vis[v] ) continue;
qu[++ed] = v;
fat[v] = u;
}
}
cc = build_vdcp(s);
gc[c].push_back(Pair(s,cc));
// gc[c][gcnt[c]] = Pair(s,cc);
// gcnt[c]++;
for( register int t=stk.size()-; t>=; t-- ) {
int u=stk[t];
info[u].push_back( Info(c,cc) );
// info[u][icnt[u]] = Info(c,cc);
// icnt[u]++;
}
}
return c;
}
dnt query( int u ) {
if( tag[u]==curt ) return rans[u];
tag[u] = curt;
dnt rt = cans[u];
for( int t=; t<info[u].size(); t++ ) {
// for( int t=icnt[u]-1; t>=0; t-- ) {
int p=info[u][t].p, s=info[u][t].s;
rt += cans[p]-fans[s]+(sumw[p]-sumw[s])*qu_dis(u,p);
}
return rans[u]=rt;
}
dnt search( int u ) {
dnt su = query(u);
for( int t=; t<gc[u].size(); t++ ) {
// for( int t=gcnt[u]-1; t>=0; t-- ) {
Pair &p = gc[u][t];
dnt a=query(p.s);
if( a<su ) return search(p.c);
}
return su;
}
void modify( int u, int delta ) {
sumw[u] += delta;
for( int t=info[u].size()-; t>=; t-- ) {
// for( int t=icnt[u]-1; t>=0; t-- ) {
int p=info[u][t].p, s=info[u][t].s;
dnt d = (dnt)delta*qu_dis(u,p);
cans[p] += d;
fans[s] += d;
sumw[p] += delta;
}
}
int main() {
scanf( "%d%d", &n, &m );
for( int i=,u,v,w; i<n; i++ ) {
scanf( "%d%d%d", &u, &v, &w );
adde( u, v, w );
adde( v, u, w );
}
bac[] = n;
int core = build_vdcp();
build_lca();
for( int t=,u,d; t<=m; t++ ) {
scanf( "%d%d", &u, &d );
modify( u, d );
curt = t;
printf( "%lld\n", search(core) );
}
}
bzoj 3924 点分的更多相关文章
- [BZOJ 4332] [JSOI2012]分零食(DP+FFT)
[BZOJ 4332] [JSOI2012]分零食(DP+FFT) 题面 同学们依次排成了一列,其中有A位小朋友,有三个共同的欢乐系数O,S和U.如果有一位小朋友得到了x个糖果,那么她的欢乐程度就是\ ...
- BZOJ 3924 / Luogu P3345 [ZJOI2015]幻想乡战略游戏 (动态点分治/点分树)
题意 树的结构不变,每个点有点权,每一条边有边权,有修改点权的操作,设xxx为树中一点.求∑idist(x,i)∗a[i]\sum_idist(x,i)*a[i]i∑dist(x,i)∗a[i]的最 ...
- bzoj 3924 [Zjoi2015]幻想乡战略游戏——动态点分治(暴力移动找重心)
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3924 度数只有20,所以从一个点暴力枚举其出边,就能知道往哪个方向走. 知道方向之后直接走到 ...
- BZOJ 4710: [Jsoi2011]分特产 [容斥原理]
4710: [Jsoi2011]分特产 题意:m种物品分给n个同学,每个同学至少有一个物品,求方案数 对于每种物品是独立的,就是分成n组可以为空,然后可以用乘法原理合起来 容斥容斥 \[ 每个同学至少 ...
- bzoj 3924: [Zjoi2015]幻想乡战略游戏
Description 傲娇少女幽香正在玩一个非常有趣的战略类游戏,本来这个游戏的地图其实还不算太大,幽香还能管得过来,但是不知道为什么现在的网游厂商把游戏的地图越做越大,以至于幽香一眼根本看不过来, ...
- ●BZOJ 4710 [Jsoi2011]分特产
题链: http://www.lydsy.com/JudgeOnline/problem.php?id=4710 题解: 容斥,组合先看看这个方案数的计算:把 M 个相同的东西分给 N 个人,每个人可 ...
- bzoj 4710: [Jsoi2011]分特产
Description JYY 带队参加了若干场ACM/ICPC 比赛,带回了许多土特产,要分给实验室的同学们. JYY 想知道,把这些特产分给N 个同学,一共有多少种不同的分法?当然,JYY 不希望 ...
- 【BZOJ 3924】[Zjoi2015]幻想乡战略游戏
题目: 题解: 对点分树理解加深了233,膜拜zzh干翻紫荆花. 感谢zzh的讲解. 首先优化基于传统DP,假设树不发生变化,我们就可以利用DP求出带权重心. 考虑修改,我们思路不变,还是从root开 ...
- bzoj 4332: JSOI2012 分零食 快速傅立叶变换
题目: Description 同学们依次排成了一列,其中有A位小朋友,有三个共同的欢乐系数O,S和U.如果有一位小朋友得到了x个糖果,那么她的欢乐程度就是\(f(x)=O*x^2+S*x+U\) 现 ...
随机推荐
- python实现监控windows服务控制开关服务
转载自 :http://www.jb51.net/article/49106.htm #!/usr/bin/env python #-*- encoding:utf-8 -*- "" ...
- GetStockObject 理解
原文地址:https://www.cnblogs.com/Clingingboy/archive/2013/04/13/3017952.html GetStockObject在图形编程中是常用API之 ...
- java项目中oracle配置说明
配置信息: #oracle database settings jdbc.url::orcl jdbc.username=cognos_data jdbc.password=cognos_data j ...
- nagios系列(四)之nagios主动方式监控tcp常用的80/3306等端口监控web/syncd/mysql及url服务
nagios主动方式监控tcp服务web/syncd/mysql及url cd /usr/local/nagios/libexec/ [root@node4 libexec]# ./check_tcp ...
- mysql数据库基于LVM快照的备份
lvm-snapshot: 基于LVM快照的备份 1.事务日志跟数据文件必须在同一个卷上 2.创建快照卷之前,要请求mysql的全局锁,在快照创建完成之后释放锁 3 ...
- mysql更新字段值提示You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column To disable safe mode
1 引言 当更新字段缺少where语句时,mysql会提示一下错误代码: Error Code: 1175. You are using safe update mode and you tried ...
- 【ES】学习5-全文搜索
全文搜索两个最重要的方面是:相关性, 分析. 一旦谈论相关性或分析这两个方面的问题时,我们所处的语境是关于查询的而不是过滤. match:单个词查询 GET /my_index/my_type/_se ...
- poj2528贴海报,,
对于区间段的离散化需要注意一下,和点离散化不同 离散后如何识别一段区间还是一段区间,而不是两个顶点,就是如果两个点的距离大于1,就往离散的数据里插入一个中间值,即用三个点来表示一段区间 /* 离散化长 ...
- hdu4052矩形面积并
建模需要注意下细节,,这是做扫描线的惯例,就是最好把模型建立在笛卡尔坐标系上 剩下的看链接和注释https://blog.csdn.net/shiqi_614/article/details/7983 ...
- hdu 3405 删掉某点后 求最小生成树
给出N个点的坐标 边的权值为两点间的距离 删掉其中某点 求最小生成树的权值和 要求这权值最小 因为最多50个点 所以具体是删哪个点 用枚举假如有4个点 就要求4次最小生成树 分别是2 3 4 | 1 ...