\(\mathcal{Description}\)

  Link.

  给定一棵含 \(n\) 个结点的树,结点 \(1\) 为根,点 \(u\) 初始有点权 \(a_u=0\),维护 \(q\) 次操作:

  1. 给定 \(u\),将 \(u\) 子树内的点权加 \(1\);
  2. 给定 \(u,v\),将 \(u,v\) 简单路径上的点权加 \(1\)。

  每次操作后,求出树最靠近结点 \(1\) 的带权重心。

  \(n,q\le10^5\)。

\(\mathcal{Solution}\)

  记点权和为 \(S\),发现这么一个事情:

从 \(1\) 开始任意 DFS 树,在经过点权和不小于 \(\lceil\frac{S}{2}\rceil\) 时停止在结点 \(x\),则带权重心为 \(x\) 及其祖先中的某一个。

当然转化在 DFN 序列上更简洁

DFN 序列的前缀和恰好超过 \(\lceil\frac{S}{2}\rceil\) 的位置就是上述 \(x\) 的 DFN。

  证明上,这样的遍历把树分为一个点权和不小于 \(\lceil\frac{S}{2}\rceil\) 的连通块 \(A\) 和若干连通块 \(B\)。注意带权重心的基本性质是以重心为根时,不存在一条连向点权和大于 \(\lfloor\frac{S}{2}\rfloor\) 的子树。首先考虑 \(B\) 中的结点 \(u\),若 \(u\) 能成为重心,其父亲必然也能成为重心,而且其父亲更靠近 \(1\),所以 \(u\) 不优;对于 \(A\) 中不是 \(x\) 祖先的结点同理,所以证明了这条性质。

  回到本题,难点已经扫除了。树剖维护点权,线段树二分找到 \(x\),倍增祖先找到重心即可。复杂度 \(\mathcal O(q\log^2n)\)。

\(\mathcal{Code}\)

/*~Rainybunny~*/

#include <cstdio>

#define rep( i, l, r ) for ( int i = l, rep##i = r; i <= rep##i; ++i )
#define per( i, r, l ) for ( int i = r, per##i = l; i >= per##i; --i ) typedef long long LL; const int MAXN = 1e5, MAXLG = 16;
int n, ecnt, head[MAXN + 5], ans = 1;
struct Edge { int to, nxt; } graph[MAXN * 2 + 5];
int fa[MAXN + 5][MAXLG + 5], siz[MAXN + 5], son[MAXN + 5], dep[MAXN + 5];
int dfc, dfn[MAXN + 5], top[MAXN + 5], ref[MAXN + 5]; inline void link( const int u, const int v ) {
graph[++ecnt] = { v, head[u] }, head[u] = ecnt;
graph[++ecnt] = { u, head[v] }, head[v] = ecnt;
} inline void init( const int u ) {
dep[u] = dep[fa[u][0]] + 1, siz[u] = 1;
for ( int i = 1; fa[u][i - 1]; fa[u][i] = fa[fa[u][i - 1]][i - 1], ++i );
for ( int i = head[u], v; i; i = graph[i].nxt ) {
if ( ( v = graph[i].to ) != fa[u][0] ) {
fa[v][0] = u, init( v ), siz[u] += siz[v];
if ( siz[v] > siz[son[u]] ) son[u] = v;
}
}
} inline void init( const int u, const int tp ) {
top[u] = tp, ref[dfn[u] = ++dfc] = u;
if ( son[u] ) init( son[u], tp );
for ( int i = head[u], v; i; i = graph[i].nxt ) {
if ( ( v = graph[i].to ) != fa[u][0] && v != son[u] ) {
init( v, v );
}
}
} struct SegmentTree {
int len[MAXN << 2];
LL sum[MAXN << 2], tag[MAXN << 2]; inline void pushad( const int u, const LL v ) {
sum[u] += len[u] * v, tag[u] += v;
} inline void pushup( const int u ) {
sum[u] = sum[u << 1] + sum[u << 1 | 1];
} inline void pushdn( const int u ) {
if ( tag[u] ) {
pushad( u << 1, tag[u] ), pushad( u << 1 | 1, tag[u] );
tag[u] = 0;
}
} inline void init( const int u, const int l, const int r ) {
len[u] = r - l + 1;
if ( l == r ) return ;
int mid = l + r >> 1;
init( u << 1, l, mid ), init( u << 1 | 1, mid + 1, r );
} inline void add( const int u, const int l, const int r,
const int al, const int ar, const int v ) {
if ( al <= l && r <= ar ) return pushad( u, v );
int mid = l + r >> 1; pushdn( u );
if ( al <= mid ) add( u << 1, l, mid, al, ar, v );
if ( mid < ar ) add( u << 1 | 1, mid + 1, r, al, ar, v );
pushup( u );
} inline LL qsum( const int u, const int l, const int r,
const int ql, const int qr ) {
if ( ql <= l && r <= qr ) return sum[u];
int mid = l + r >> 1; LL ret = 0; pushdn( u );
if ( ql <= mid ) ret += qsum( u << 1, l, mid, ql, qr );
if ( mid < qr ) ret += qsum( u << 1 | 1, mid + 1, r, ql, qr );
return ret;
} inline int qhalf( const int u, const int l, const int r, const LL h ) {
if ( l == r ) return l;
int mid = l + r >> 1; pushdn( u );
if ( sum[u << 1] >= h ) return qhalf( u << 1, l, mid, h );
else return qhalf( u << 1 | 1, mid + 1, r, h - sum[u << 1] );
}
} sgt; inline void subtrAdd( const int u ) {
sgt.add( 1, 1, n, dfn[u], dfn[u] + siz[u] - 1, 1 );
} inline void chainAdd( int u, int v ) {
while ( top[u] != top[v] ) {
if ( dep[top[u]] < dep[top[v]] ) u ^= v ^= u ^= v;
sgt.add( 1, 1, n, dfn[top[u]], dfn[u], 1 ), u = fa[top[u]][0];
}
if ( dep[u] < dep[v] ) u ^= v ^= u ^= v;
sgt.add( 1, 1, n, dfn[v], dfn[u], 1 );
} inline void solve() {
int u = ref[sgt.qhalf( 1, 1, n, sgt.sum[1] + 1 >> 1 )];
per ( i, MAXLG, 0 ) {
int v = fa[u][i];
if ( v && sgt.qsum( 1, 1, n, dfn[v],
dfn[v] + siz[v] - 1 ) << 1 <= sgt.sum[1] ) {
u = fa[v][0];
}
}
if ( fa[u][0] && sgt.qsum( 1, 1, n, dfn[u],
dfn[u] + siz[u] - 1 ) << 1 <= sgt.sum[1] ) u = fa[u][0];
printf( "%d\n", u );
} int main() {
scanf( "%d", &n );
rep ( i, 2, n ) {
int u, v; scanf( "%d %d", &u, &v );
link( u, v );
} init( 1 ), init( 1, 1 ), sgt.init( 1, 1, n ); int q, op, u, v; scanf( "%d", &q );
while ( q-- ) {
scanf( "%d %d", &op, &u );
if ( op == 1 ) subtrAdd( u );
else scanf( "%d", &v ), chainAdd( u, v );
solve();
}
return 0;
}

Solution -「Gym 102759I」Query On A Tree 17的更多相关文章

  1. Solution -「Gym 102979E」Expected Distance

    \(\mathcal{Description}\)   Link.   用给定的 \(\{a_{n-1}\},\{c_n\}\) 生成一棵含有 \(n\) 个点的树,其中 \(u\) 连向 \([1, ...

  2. Solution -「Gym 102979L」 Lights On The Road

    \(\mathcal{Description}\)   Link.   给定序列 \(\{w_n\}\),选择 \(i\) 位置的代价为 \(w_i\),要求每个位置要不被选择,要不左右两个位置至少被 ...

  3. Solution -「Gym 102956F」Find the XOR

    \(\mathcal{Description}\)   Link.   给定 \(n\) 个点 \(m\) 条边的连通无向图 \(G\),边有边权.其中 \(u,v\) 的距离 \(d(u,v)\) ...

  4. Solution -「Gym 102956B」Beautiful Sequence Unraveling

    \(\mathcal{Description}\)   Link.   求长度为 \(n\),值域为 \([1,m]\) 的整数序列 \(\lang a_n\rang\) 的个数,满足 \(\not\ ...

  5. Solution -「Gym 102956F」Border Similarity Undertaking

    \(\mathcal{Description}\)   Link.   给定一张 \(n\times m\) 的表格,每个格子上写有一个小写字母.求其中长宽至少为 \(2\),且边界格子上字母相同的矩 ...

  6. Solution -「Gym 102956A」Belarusian State University

    \(\mathcal{Description}\)   Link.   给定两个不超过 \(2^n-1\) 次的多项式 \(A,B\),对于第 \(i\in[0,n)\) 个二进制位,定义任意一个二元 ...

  7. Solution -「Gym 102798I」Sean the Cuber

    \(\mathcal{Description}\)   Link.   给定两个可还原的二阶魔方,求从其中一个状态拧到另一个状态的最小步数.   数据组数 \(T\le2.5\times10^5\). ...

  8. Solution -「Gym 102798K」Tree Tweaking

    \(\mathcal{Description}\)   Link.   给定排列 \(\{p_n\}\),求任意重排 \(p_{l..r}\) 的元素后,将 \(\{p_n\}\) 依次插入二叉搜索树 ...

  9. Solution -「Gym 102798E」So Many Possibilities...

    \(\mathcal{Description}\)   Link.   给定非负整数序列 \(\{a_n\}\) 和 \(m\),每次随机在 \(\{a\}\) 中取一个非零的 \(a_i\)(保证存 ...

随机推荐

  1. mysql数据库忘记root密码怎么办?

    mysql数据库忘记root密码怎么破解和修改 1.停止数据库的运行 [root@localhost ~]# /etc/init.d/mysqld stop 或者[root@localhost ~]# ...

  2. wordpress搭建网站更改域名后打开网页排版显示错乱解决办法

    发生的原因: 我本来已经搭建好了网站,也测试了没问题.后来更改了网站的域名,出现了这种情况. 解决办法: 需要修改数据库的options表里面的 siteurl 和 home 这两个表的内容为最新的域 ...

  3. Python爬取中国知网文献、参考文献、引证文献

    前两天老师派了个活,让下载知网上根据高级搜索得到的来源文献的参考文献及引证文献数据,网上找了一些相关博客,感觉都不太合适,因此特此记录,希望对需要的人有帮助. 切入正题,先说这次需求,高级搜索,根据中 ...

  4. JAVA之G1垃圾回收器

    概述 G1 GC,全称Garbage-First Garbage Collector,通过-XX:+UseG1GC参数来启用,作为体验版随着JDK 6u14版本面世,在JDK 7u4版本发行时被正式推 ...

  5. MySQL提权之启动项提权

    关于MySQL的启动项提权,听其名知其意.就是将一段 VBS脚本导入到  C:\Documents and Settings\All Users\「开始」菜单\程序\启动 下,如果管理员重启了服务器, ...

  6. docker创建mysql容器时挂载文件路径后无法启动(已解决)

    系统centos7 docker版本: 解决方法: 在docker run中加入 --privileged=true  给容器加上特定权限,如下 docker run --privileged=tru ...

  7. VUE3 之 全局组件与局部组件

    1. 概述 老话说的好:忍耐是一种策略,同时也是一种性格磨炼. 言归正传,今天我们来聊聊 VUE 的全局组件与局部组件. 2. 全局组件 2.1 不使用组件的写法  <body> < ...

  8. Web开发之Servlet

    当一个请求到达服务端,服务器怎么处理? 当一个请求到达服务端时,由服务端的引擎来进行分析.它根据工程名找到工程, 然后拿到URL的资源地址和web.XML文件的所有的进行对比,和哪一个对比上就找到了具 ...

  9. 如何修改主机名hostname

    hostname是Linux系统下的一个内核参数,它保存在/proc/sys/kernel/hostname下,但是它的值是Linux启动时从rc.sysinit读取的.而/etc/rc.d/rc.s ...

  10. java ++ -- 异或 短路与 短路或 三目条件

    public class Demo { public static void main(String[] args) { int i1 = 12, i2 = 20; int i = (i2++); S ...