bzoj3589 动态树

链接

bzoj

思路

求链并。

发现只有最多5条链子,可以容斥。

链交求法:链顶是两条链顶深度大的那个,链底是两个链底的\(lca\)

如果链底深度小于链顶,就说明两条链没有交集。

复杂度\(m*2^klog^2n\)

还有一种做法。

把所有链子都打上\(0/1tag\),只有\(1\)才能有贡献。

应该挺麻烦的,或者说都挺好写的。

代码

#include <bits/stdc++.h>
using namespace std;
const int _=4e5+7;
int read() {
int x=0,f=1;char s=getchar();
for(;s>'9'||s<'0';s=getchar()) if(s=='-') f=-1;
for(;s>='0'&&s<='9';s=getchar()) x=x*10+s-'0';
return x*f;
}
int n,Q,S[6],T[6];
struct node {int v,nxt;}e[_<<1];
int head[_],tot;
void add(int u,int v) {
e[++tot].v=v;
e[tot].nxt=head[u];
head[u]=tot;
}
namespace seg {
#define ls rt<<1
#define rs rt<<1|1
struct node {int l,r,siz,tot,lazy;}e[_<<2];
void build(int l,int r,int rt) {
e[rt].l=l,e[rt].r=r,e[rt].siz=r-l+1;
if(l==r) return;
int mid=(l+r)>>1;
build(l,mid,ls);
build(mid+1,r,rs);
}
void pushdown(int rt) {
if(e[rt].lazy) {
e[ls].tot+=e[ls].siz*e[rt].lazy;
e[rs].tot+=e[rs].siz*e[rt].lazy;
e[ls].lazy+=e[rt].lazy;
e[rs].lazy+=e[rt].lazy;
e[rt].lazy=0;
}
}
void modify(int L,int R,int ad,int rt) {
if(L<=e[rt].l&&e[rt].r<=R) {
e[rt].tot+=e[rt].siz*ad;
e[rt].lazy+=ad;
return;
}
int mid=(e[rt].l+e[rt].r)>>1;
pushdown(rt);
if(L<=mid) modify(L,R,ad,ls);
if(R>mid) modify(L,R,ad,rs);
e[rt].tot=e[ls].tot+e[rs].tot;
}
int query(int L,int R,int rt) {
if(L<=e[rt].l&&e[rt].r<=R) return e[rt].tot;
int mid=(e[rt].l+e[rt].r)>>1,ans=0;
pushdown(rt);
if(L<=mid) ans+=query(L,R,ls);
if(R>mid) ans+=query(L,R,rs);
return ans;
}
}
int dep[_],f[_],siz[_],son[_],top[_],idx[_],cnt;
void dfs1(int u,int fa) {
dep[u]=dep[fa]+1;
siz[u]=1;
f[u]=fa;
for(int i=head[u];i;i=e[i].nxt) {
int v=e[i].v;
if(v==fa) continue;
dfs1(v,u);
siz[u]+=siz[v];
if(siz[v]>siz[son[u]]) son[u]=v;
}
}
void dfs2(int u,int topf) {
idx[u]=++cnt;
top[u]=topf;
if(!son[u]) return;
dfs2(son[u],topf);
for(int i=head[u];i;i=e[i].nxt) {
int v=e[i].v;
if(!idx[v]) dfs2(v,v);
}
}
int LCA(int x,int y) {
while(top[x]!=top[y]) {
if(dep[top[x]]<dep[top[y]]) swap(x,y);
x=f[top[x]];
} if(dep[x]>dep[y]) swap(x,y);
return x;
}
int QQ(int x,int y) {
int tot=0;
while(top[x]!=top[y]) {
if(dep[top[x]]<dep[top[y]]) swap(x,y);
tot+=seg::query(idx[top[x]],idx[x],1);
x=f[top[x]];
}
if(dep[x]>dep[y]) swap(x,y);
tot+=seg::query(idx[x],idx[y],1);
return tot;
}
void dsrrr(int &a,int &b,int x,int y) {
a=dep[a]>dep[x]?a:x,b=LCA(b,y);
if(dep[b]<dep[a]) a=-1,b=-1;
}
int calc(int x) {
int s=0,t=0;
for(int i=1;x;i++,x>>=1) {
if(x&1) {
if(!s&&!t) s=S[i],t=T[i];
else dsrrr(s,t,S[i],T[i]);
} if(s==-1&&t==-1) return 0;
}
return QQ(s,t);
}
int man[40];
int main() {
n=read();
for(int i=1,u,v;i<n;++i) {
u=read(),v=read();
add(u,v),add(v,u);
}
seg::build(1,n,1);
dfs1(1,0),dfs2(1,1);
Q=read();
for(int i=1;i<(1<<5);++i)
for(int j=0;j<5;++j)
if(i&(1<<j)) man[i]++;
while (Q --> 0) {
int opt=read();
if(!opt) {
int u=read(),val=read();
seg::modify(idx[u],idx[u]+siz[u]-1,val,1);
} else {
int k=read();
for(int i=1;i<=k;++i) {
S[i]=read(),T[i]=read();
if(dep[S[i]]>dep[T[i]]) swap(S[i],T[i]);
}
int ans=0;
for(int i=1;i<(1<<k);++i)
ans+=(man[i]&1?1:-1)*calc(i);
printf("%d\n",ans&2147483647);
}
}
return 0;
}

bzoj3589 动态树 求链并 容斥的更多相关文章

  1. bzoj3589 动态树 树链剖分+容斥

    题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=3589 题解 事件 \(0\) 不需要说,直接做就可以了. 事件 \(1\) 的话,考虑如果直接 ...

  2. BZOJ3589 动态树[树剖/暴力/容斥]

    操作0,显然直接线段树解决. 操作1,瓶颈在于重叠的链只算一次.在线段树上来看,如果一个区间被覆盖了,那么只算这个区间,子树里面也就不管了. 考虑对节点打标记来表示是否覆盖.但是,如果统一打完之后,并 ...

  3. bzoj 3589: 动态树【树链剖分+容斥】

    因为一开始调试不知道unsigned怎么输出就没有加\n结果WA了一上午!!!!!然而最后放弃了unsigned选择了&2147483647 首先链剖,因为它所给的链一定是某个点到根的路径上的 ...

  4. BZOJ3589 动态树(树链剖分+容斥原理)

    显然容斥后转化为求树链的交.这个题非常良心的保证了查询的路径都是到祖先的,求交就很休闲了. #include<iostream> #include<cstdio> #inclu ...

  5. [树链剖分]BZOJ3589动态树

    题目描述 别忘了这是一棵动态树, 每时每刻都是动态的. 小明要求你在这棵树上维护两种事件 事件0: 这棵树长出了一些果子, 即某个子树中的每个节点都会长出K个果子. 事件1: 小明希望你求出几条树枝上 ...

  6. hdu 5664 Lady CA and the graph(树的点分治+容斥)

    题意: 给你一个有n个点的树,给定根,叫你找第k大的特殊链 .特殊的链的定义:u,v之间的路径,经过题给的根节点. 题解:(来自BC官方题解) 对于求第k大的问题,我们可以通过在外层套一个二分,将其转 ...

  7. hdu 5792(树状数组,容斥) World is Exploding

    hdu 5792 要找的无非就是一个上升的仅有两个的序列和一个下降的仅有两个的序列,按照容斥的思想,肯定就是所有的上升的乘以所有的下降的,然后再减去重复的情况. 先用树状数组求出lx[i](在第 i ...

  8. Luogu4528 CTSC2008 图腾 树状数组、容斥

    传送门 设$f_i$表示$i$排列的数量,其中$x$表示不确定 那么$$ans=f_{1324}-f_{1432}-f_{1243}=(f_{1x2x}-f_{1423})-(f_{14xx}-f_{ ...

  9. JZOJ 5987 仙人掌毒题 (树链剖分 + 容斥)

    跟仙人掌其实没啥关系- Here 注意 每一次都O(n)O(n)O(n)一下算某些点都是黑点的概率其实并不是O(n2)O(n^2)O(n2),因为每个环只用算一次. #include <ccty ...

随机推荐

  1. laravel5.5框架中视图间如何共享数据?视图间共享数据的两种方法

    laravel框架中视图间共享数据有两种,一种是用视图门面share()方法实现,另一种是用视图门面composer() 方法实现,那么,两种方法的实现究竟是怎样的呢?让我们来看一看接下来的文章内容. ...

  2. Java8 新特性 Stream 无状态中间操作

    无状态中间操作 Java8 新特性 Stream 练习实例 中间无状态操作,可以在单个对单个的数据进行处理.比如:filter(过滤)一个元素的时候,也可以判断,比如map(映射)... 过滤 fil ...

  3. Sitecore 十大优秀功能

    为客户的需求创建最佳解决方案是我们的主要目标.良好的设计不仅仅是视觉吸引力,还要确保用户体验简单直观.在设计Sitecore网站时,我们始终牢记这一点  . 以下是一些我最喜欢的功能,可以帮助我们使用 ...

  4. JS中判断是中文数字的函数

    function checkcnnum(str) { ; const zh = ['零', '一', '二', '三', '四', '五', '六', '七', '八', '九','十','百','千 ...

  5. Client 客户端AspNetCore.SignalR 通讯服务器 Quartz 执行任务

    背景 需要Client跑服务在终端间隔执行任务,我的目标是运行在树莓派上 Client代码 如果未连接成功时隔3秒重新连接服务器 public static void Reconnect() { va ...

  6. Reactor的NIO线程模型

    1.Reactor单线程模型 传统的javaNIO通信的线程模型.该线程模型仅有一个I/O线程处理所有的I/O操作,如下图:   单线程模型的Reactor 所有的客户端都连接到一个I/O线程负责的A ...

  7. Python: 截屏

    最近项目中想实现截屏功能,使用的笔记本是高清屏,实际屏幕设置成了150%,所以在截屏的时候遇到个各种问题. 最开始使用PIL ImageGrab来截取屏幕,如果本来是100%的设置没有问题,能截取到全 ...

  8. tf.image.adjust_brightness等的使用

    import tensorflow as tfimport numpy as npimport cv2 as cvimport matplotlib.pyplot as pltsess=tf.Sess ...

  9. Java自学-I/O 缓存流

    Java 缓存流BufferedReader,PrintWriter 以介质是硬盘为例,字节流和字符流的弊端: 在每一次读写的时候,都会访问硬盘. 如果读写的频率比较高的时候,其性能表现不佳. 为了解 ...

  10. python数据分析三剑客之: matplotlib绘图模块

    matplotlib 一.Matplotlib基础知识 Matplotlib中的基本图表包括的元素 - x轴和y轴 axis 水平和垂直的轴线 - x轴和y轴刻度 tick 刻度标示坐标轴的分隔,包括 ...