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. charles基本使用文档

    Charles 主要的功能包括: 截取 Http 和 Https 网络封包. 支持重发网络请求,方便后端调试. 支持修改网络请求参数. 支持网络请求的截获并动态修改. 支持模拟慢速网络. Charle ...

  2. [C++]boost dijkstra获得两点间的最短路

    需求是只需要得到两点间的最短路,不需要求得单源对于全图的最短路,使用boost中的dijsktra_shortest_path,当得到目标点的最短路时直接throw exception. #inclu ...

  3. dubbo 微服务

    # spring-dubbo-service 微服务 项目地址:https://github.com/windwant/spring-dubbo-service spring dubbo servic ...

  4. MySQL高性能优化实战总结

    1.1 前言 MySQL对于很多Linux从业者而言,是一个非常棘手的问题,多数情况都是因为对数据库出现问题的情况和处理思路不清晰.在进行MySQL的优化之前必须要了解的就是MySQL的查询过程,很多 ...

  5. 【python 3.6】如何将list存入txt后,再读出list

    今天遇到一个需求,就是将一个list文件读取后,存入一个txt配置文件.存入时,发现list文件无法直接存入,必须转为str模式. 但在读取txt时,就无法恢复成list类型来读取了(准确地说,即使强 ...

  6. AWS/阿里/Azure,云厂商价格大PK

    以下选取热门型号Linux虚拟机,AWS和Azure的虚拟机配置包括本地SSD临时盘,阿里云虚拟机不带本地SSD临时盘,而且需要另配网卡带宽.以下价格为人民币含税(6%) 按使用量网站直接付费购买(O ...

  7. 笔试题——C++字符排序

    题目:字符排序 题目介绍:输入一组以空格隔开的字数串,将它们奇数位升序排序,偶数位降序排序,再重新输出成新的字数串. 例: 输入: 4 6 2 3 6 7 8 1 奇数位:4 2 6 8 ——2 4 ...

  8. 所见即所得:七大无需编程的DIY开发工具

    现如今,各种DIY开发工具不断的出现,使得企业和个人在短短几分钟内就能完成应用的创建和发布,大大节省了在时间和资金上的投入.此外,DIY工具的出现,也帮助广大不具备专业知识和技术的“移动开发粉”创建自 ...

  9. txt文件存储问题

    一.实际大小与占用空间不一致: 1.占用空间和磁盘有关,一般磁盘存储最小大小为4kb(4096字节). 2.当txt文件中仅有1个数字‘5’的时候,大小显示为1个字节(属性看,列表详细不精确),占用空 ...

  10. win10自带中文输入法的用户体验

    用户界面: 貌似没有什么界面,不过我感觉这就是最大的优点,没有过度渲染的界面,没有烦人的推送.弹窗,没有定期不定期的更新提示,简洁也是我使用这款输入法的最主要的原因 记住用户的选择: 这点我认为win ...