Portal --> bzoj3589

Description

  给你一棵\(n\)个节点的树,总共有\(q\)次操作,每次操作是以下两种中的一种:

操作\((0,x,delta)\):给以\(x\)为根的子树中每个节点的点权\(+delta\)

操作\((1,k,(x_1,y_1),(x_2,y_2)...(x_k,y_k))\):求\(k\)条链的并的权值之和,一个节点集合的权值之和定义为该集合中所有节点的点权之和

  点权初始为\(0\),链保证是某个节点到根的路径上的某一段

​  数据范围:\(1<=n,q<=2*10^5,1<=k<=5\)

Solution

  这题的话。。虽然说网上好像有根本不需要用到容斥和链的特性直接一个线段树就可以搞定的做法。。但是我不会qwq所以还是容斥吧qwq

​  因为这题中的链有十分优秀的性质,都是到根路径上的某一段,所以我们考虑维护每一个节点到根的路径上的点权和,这样一旦求得并问题就很好解决了

​  子树加操作的话直接用树剖+线段树或者树状数组来搞就好了

​  线段树直接搞就不讲了,如果用树状数组的话就是开两个支持区间修改单点查询的树状数组

​  我们考虑对于一次修改操作\((x,delta)\),\(y\)是\(x\)子树中的一个节点,考虑这次修改对\(y\)这个位置的值的影响,应该是加上\((dep[y]-(dep[x]-1))*delta\)

​  那么我们可以考虑前面的\(dep[y]*delta\)和\(-(dep[x]-1)*delta\)分开维护

​  我们在一个BIT(记为BIT1)中的\(x\)子树范围内的每个节点\(+(dep[x]-1)*delta\),然后在另一个BIT(记为BIT2)中的\(x\)子树范围内每个节点\(+delta\)

​  最后查询就直接BIT2::query(x)*dep[x]-BIT1::query(x),就能够得到\(x\)到根路径上所有节点的权值和了(当然你也可以第二个BIT修改的时候是\(+dep[x]*delta\),查询的时候就不用在外面乘\(dep[x]\),一样的)

​​  

​  接下来就是求并了

  

​  首先注意到每次询问的这个链的数量十分少,并且因为这个链必定是某个节点到根的路径上的一段,所以求两条这样的链的交集其实是很容易的(求个lca然后判断一下什么的就好了)

​  但是求并是一个。。很困难的过程。。

  所以我们考虑用容斥将求并转化为求交,具体一点的话就是集合容斥的这条式子:

\[|\bigcup\limits_{i=1}^{n}A_i|=\sum\limits_{k=1}^{n}(-1)^{k-1}\sum\limits_{1<=j_1<j_2<...<j_k<=n}|A_{j_1}\cap A_{j_2}\cap ...\cap A_{j_k}|
\]

  只不过我们这里用来容斥的东西不是集合的大小而是集合中元素的和:

\[sum(\bigcup\limits_{i=1}^{n}A_i)=\sum\limits_{k=1}^{n}(-1)^{k-1}\sum\limits_{1<=j_1<j_2<...<j_k<=n}sum(A_{j_1}\cap A_{j_2}\cap ...\cap A_{j_k})
\]

  然后链的数量又特别小所以直接\(2^{num}\)枚举一下就好了(其中\(num\)表示的是链的数量)

  (这里提醒一下自己。。枚举的时候可以用状压的方式来操作,这样比dfs不知道高到哪里去了qwq)

  最后还有一点就是,对\(2^{31}\)取模可以int自然溢出最后再和maxlongint取个与就好了

  

​  代码大概长这个样子

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
const int N=2*(1e5)+10,TOP=20;
struct xxx{
int y,nxt;
}a[N*2];
struct L{
int x,y;
L(){}
L(int _x,int _y){x=_x; y=_y;}
}rec[6],tmp;
int h[N],lis[N*2],st[N],dep[N],pre[N];
int mn[N*2][TOP+1];
int dfn[N],dfned[N];
int n,m,tot,dfn_t,dfn_t1;
namespace BIT{/*{{{*/
int c[N*2],rt[2];
int n;
void init(int _n){n=_n;rt[0]=0; rt[1]=n;}
void _add(int St,int x,int delta){
for (;x<=n;x+=x&-x) c[St+x]+=delta;
}
void add(int which,int x,int delta){_add(rt[which],dfn[x],delta);_add(rt[which],dfned[x]+1,-delta);}
int _query(int St,int x){
int ret=0;
for (;x;x-=x&-x) ret+=c[St+x];
return ret;
}
int query(int x){
if (!x) return 0;
return _query(rt[1],dfn[x])*dep[x]-_query(rt[0],dfn[x]);
}
}/*}}}*/
void add(int x,int y){a[++tot].y=y; a[tot].nxt=h[x]; h[x]=tot;}
void dfs(int fa,int x,int d){
int u;
st[x]=++dfn_t; lis[dfn_t]=x; dep[x]=d; pre[x]=fa;
dfn[x]=++dfn_t1;
for (int i=h[x];i!=-1;i=a[i].nxt){
u=a[i].y;
if (u==fa) continue;
dfs(x,u,d+1);
lis[++dfn_t]=x;
}
dfned[x]=dfn_t1;
}
void prework(){
BIT::init(n);
lis[0]=dfn_t;
for (int i=1;i<=lis[0];++i) mn[i][0]=lis[i];
for (int j=1;j<=TOP;++j)
for (int i=lis[0]-(1<<j)+1;i>=1;--i)
if (dep[mn[i][j-1]]<dep[mn[i+(1<<j-1)][j-1]])
mn[i][j]=mn[i][j-1];
else
mn[i][j]=mn[i+(1<<j-1)][j-1];
}
int get_lca(int x,int y){
x=st[x]; y=st[y];
if (x>y) swap(x,y);
int len=y-x+1,lg=(int)(log(1.0*len)/log(2.0));
if (dep[mn[x][lg]]<dep[mn[y-(1<<lg)+1][lg]]) return mn[x][lg];
else return mn[y-(1<<lg)+1][lg];
}
void merge(L &x,L y){
if (x.x==0&&x.y==0) return;
int lca;
if (dep[x.x]<dep[y.x]){
lca=get_lca(x.y,y.x);
if (lca!=y.x){x=L(0,0); return;}
lca=get_lca(x.y,y.y);
x=L(y.x,lca);
}
else{
lca=get_lca(y.y,x.x);
if (lca!=x.x){x=L(0,0); return;}
lca=get_lca(y.y,x.y);
x=L(x.x,lca);
}
}
int get_val(L x){
return BIT::query(x.y)-BIT::query(pre[x.x]);
}
void solve(int num){
int all=1<<num,mark,ans=0;
for (int i=1;i<all;++i){
mark=-1;
tmp=L(-1,-1);
for (int j=1;j<=num;++j)
if (i>>(j-1)&1){
mark*=-1;
if (tmp.x==-1&&tmp.y==-1)
tmp.x=rec[j].x,tmp.y=rec[j].y;
else
merge(tmp,rec[j]);
}
ans+=mark*get_val(tmp);
}
printf("%d\n",ans&2147483647);
}
void debug(){
for (int i=1;i<=n;++i) printf("%d ",BIT::query(i));
printf("\n");
} int main(){
#ifndef ONLINE_JUDGE
freopen("a.in","r",stdin);
#endif
int x,y,delta,num,op;
scanf("%d",&n);
memset(h,-1,sizeof(h));
tot=0;
for (int i=1;i<n;++i){
scanf("%d%d",&x,&y);
add(x,y); add(y,x);
}
dfn_t=0; dfn_t1=0;
dfs(0,1,1);
prework();
scanf("%d",&m);
for (int i=1;i<=m;++i){
scanf("%d",&op);
if (op==0){
scanf("%d%d",&x,&delta);
BIT::add(0,x,(dep[x]-1)*delta);
BIT::add(1,x,delta);
}
else{
scanf("%d",&num);
for (int j=1;j<=num;++j){
scanf("%d%d",&rec[j].x,&rec[j].y);
if (dep[rec[j].x]>dep[rec[j].y]) swap(rec[j].x,rec[j].y);
}
solve(num);
}
//debug();
}
}

【bzoj3589】动态树的更多相关文章

  1. bzoj3589 动态树 求链并 容斥

    bzoj3589 动态树 链接 bzoj 思路 求链并. 发现只有最多5条链子,可以容斥. 链交求法:链顶是两条链顶深度大的那个,链底是两个链底的\(lca\) 如果链底深度小于链顶,就说明两条链没有 ...

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

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

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

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

  4. BZOJ3589 : 动态树

    对于既要支持子树修改又要支持链查询, 需要树链剖分 然后求出DFS序,DFS的时候先DFS重儿子, 然后子树是1个区间,链是$O(\log n)$个区间 这道题对于查询若干条链的并: 由于K<= ...

  5. bzoj千题计划214:bzoj3589: 动态树

    http://www.lydsy.com/JudgeOnline/problem.php?id=3589 树链剖分 用线段数维护扫描线的方式来写,标记只打不下传 #include<cstdio& ...

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

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

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

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

  8. BZOJ3589动态树

    **错误改了一上午. 先做熟练泼粪 k<=5,因此我们可以模拟这个过程,在线段树上把标记建出来然后pushup时候更新就好了. By:大奕哥 #include<bits/stdc++.h& ...

  9. 【BZOJ-3589】动态树 树链剖分 + 线段树 + 线段覆盖(特殊的技巧)

    3589: 动态树 Time Limit: 30 Sec  Memory Limit: 1024 MBSubmit: 405  Solved: 137[Submit][Status][Discuss] ...

  10. 【BZOJ3589】动态树 树链剖分+线段树

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

随机推荐

  1. POJ 2251 Dungeon Master (三维BFS)

    题目链接:http://poj.org/problem?id=2251 Dungeon Master Time Limit: 1000MS   Memory Limit: 65536K Total S ...

  2. SQL Server临时表漫谈

    SQL Server是微软的关系型数据库,对于刚入门的我是一个非常友好的开发工具.可视化界面的安装与操作,非常适合刚入门的我. 其实大家要找这方面的资料,在网上一搜一大堆,这里我就不赘述那些了,基本都 ...

  3. HP VC模块Server Profile配置快速参考(With SUS)

    以管理员身份登录VCM 准备进行Server Profiles的配置 在左侧导航栏中找到并点击"Server Profiles",在右侧主窗口的左下角点击"Add&quo ...

  4. 使用calendar日历插件实现动态展示会议信息

    效果图如下,标红色为有会议安排,并跳转详细会议信息页面. html页面 <%@ page contentType="text/html;charset=UTF-8"%> ...

  5. Python20-Day01

    简述编译型与解释型语言的区别,且分别列出你知道的哪些语言属于编译型,哪些属于解释 编译型语言是一种以编译器来实现的编程语言,优缺点:执行速度快,调试麻烦 编译型语言:Java,Go,C,C++ 解释性 ...

  6. Numpy and Pandas

    安装 视频链接:https://morvanzhou.github.io/tutorials/data-manipulation/np-pd/ pip install numpy pip instal ...

  7. DP----入门的一些题目(POJ1088 POJ1163 POJ1050)

    动态规划入门 DP 基本思想 具体实现 经典题目 POJ1088 POJ1163 POJ1050 (一) POJ1088,动态规划的入门级题目.嘿嘿,连题目描述都是难得一见的中文. 题目分析: 求最长 ...

  8. HDU 1257 最少拦截系统(最长递减子序列的条数)

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=1257 题解: #include<iostream> #include<cstdio ...

  9. 解决Max retries exceeded with url的问题

    requests.exceptions.ConnectionError: HTTPSConnectionPool(host='itunes.apple.com', port=443): Max ret ...

  10. 使用.bat文件运行ant的build.xml

    1.新建一个txt文件 2.复制下面命令到txt文件 echo "Start build..." call ant.bat -f "E:\build.xml" ...