BZOJ3589 : 动态树
对于既要支持子树修改又要支持链查询,
需要树链剖分
然后求出DFS序,DFS的时候先DFS重儿子,
然后子树是1个区间,链是$O(\log n)$个区间
这道题对于查询若干条链的并:
由于K<=5,所以考虑容斥原理
转化为查询若干条链的交,
假设有5条链ABCDE要求交
可以先求AB的交T,再求TC的交…
考虑如何求两条树链的交:
本题中树链保证是父亲到儿子
设两条链为(a,b)(x,y),b是a的父亲,y是x的父亲
保存的交是(a',b')
c=lca(a,x)
如果c比b高或者c比y高,那么交集为空
否则a'=c
如果y在b的下面,那么b'=y,否则b'=b
每次查询$O(2^k(k\log n+\log^2n))$
常数优化:
因为对$2^{31}$取模,所以直接用int自然溢出即可,可快一倍
#include<cstdio>
#include<algorithm>
#define N 200010
#define K 17
using namespace std;
int n,i,q,x,y,k,op,ed,g[N],v[N<<1],nxt[N<<1],st[N],en[N],dfn,d[N],f[N][18],son[N],size[N],top[N],ques[6][2],ans;
inline void read(int&a){
char c;bool f=0;a=0;
while(!((((c=getchar())>='0')&&(c<='9'))||(c=='-')));
if(c!='-')a=c-'0';else f=1;
while(((c=getchar())>='0')&&(c<='9'))(a*=10)+=c-'0';
if(f)a=-a;
}
inline void addedge(int x,int y){v[++ed]=y;nxt[ed]=g[x];g[x]=ed;}
inline int lca(int x,int y){
if(x==1||y==1)return 1;
if(x==y)return x;
if(d[x]<d[y])swap(x,y);
for(int i=K;~i;i--)if(d[f[x][i]]>=d[y])x=f[x][i];
if(x==y)return x;
for(int i=K;~i;i--)if(f[x][i]!=f[y][i])x=f[x][i],y=f[y][i];
return f[x][0];
}
void dfs1(int x,int pre){
size[x]=1;d[x]=d[pre]+1;
int heavy=0,sizemax=0,i;
for(f[x][0]=pre,i=1;i<=K;i++)f[x][i]=f[f[x][i-1]][i-1];
for(i=g[x];i;i=nxt[i])if(v[i]!=pre){
dfs1(v[i],x),size[x]+=size[v[i]];
if(size[v[i]]>sizemax)sizemax=size[v[i]],heavy=v[i];
}
if(heavy)son[x]=heavy;
}
void dfs2(int x,int pre,int t){
st[x]=++dfn;top[x]=t;
if(son[x])dfs2(son[x],x,t);
for(int i=g[x];i;i=nxt[i])if(v[i]!=pre&&v[i]!=son[x])dfs2(v[i],x,v[i]);
en[x]=dfn;
}
int tot,l[N<<1],r[N<<1],len[N<<1],val[N<<1],tag[N<<1];
int build(int a,int b){
int x=++tot;
len[x]=b-a+1;
if(a==b)return x;
int mid=(a+b)>>1;
l[x]=build(a,mid);r[x]=build(mid+1,b);
return x;
}
inline void add1(int x,int p){if(!x)return;val[x]+=len[x]*p;tag[x]+=p;}
inline void pb(int x){if(tag[x]!=0)add1(l[x],tag[x]),add1(r[x],tag[x]),tag[x]=0;}
inline void up(int x){val[x]=val[l[x]]+val[r[x]];}
void add(int x,int a,int b,int c,int d,int p){
if(c<=a&&b<=d){add1(x,p);return;}
int mid=(a+b)>>1;
pb(x);
if(c<=mid)add(l[x],a,mid,c,d,p);
if(d>mid)add(r[x],mid+1,b,c,d,p);
up(x);
}
int ask(int x,int a,int b,int c,int d){
if(c<=a&&b<=d)return val[x];
int mid=(a+b)>>1,t=0;
pb(x);
if(c<=mid)t+=ask(l[x],a,mid,c,d);
if(d>mid)t+=ask(r[x],mid+1,b,c,d);
up(x);
return t;
}
inline int query(int x,int y){
if(x<1)return 0;
int t=0;
while(top[x]!=top[y])t+=ask(1,1,n,st[top[x]],st[x]),x=f[top[x]][0];
return t+ask(1,1,n,st[y],st[x]);
}
inline void merge(int&a,int&b,int x,int y){
if(a==0)return;
if(a==-1){a=x,b=y;return;}
int c=lca(a,x);
if(d[c]<d[b]||d[c]<d[y]){a=b=0;return;}
a=c;
if(d[b]<d[y])b=y;
}
void dfs(int x,int a,int b,int o){
merge(a,b,ques[x][0],ques[x][1]);
int t=query(a,b);
if(!o)ans-=t;else ans+=t;
for(x++;x<=k;x++)dfs(x,a,b,o^1);
}
int main(){
read(n);
for(i=1;i<n;i++)read(x),read(y),addedge(x,y),addedge(y,x);
dfs1(1,0);dfs2(1,0,1);
build(1,n);
read(q);
while(q--){
read(op);
if(op){
read(k);
for(i=1;i<=k;i++){
read(ques[i][0]),read(ques[i][1]);
if(d[ques[i][0]]<d[ques[i][1]])swap(ques[i][0],ques[i][1]);
}
ans=0;
for(i=1;i<=k;i++)dfs(i,-1,-1,1);
if(ans<0)ans+=(~0U>>1)+1;
printf("%d\n",ans);
}else{
read(x),read(y);
add(1,1,n,st[x],en[x],y);
}
}
return 0;
}
BZOJ3589 : 动态树的更多相关文章
- bzoj3589 动态树 求链并 容斥
bzoj3589 动态树 链接 bzoj 思路 求链并. 发现只有最多5条链子,可以容斥. 链交求法:链顶是两条链顶深度大的那个,链底是两个链底的\(lca\) 如果链底深度小于链顶,就说明两条链没有 ...
- [树链剖分]BZOJ3589动态树
题目描述 别忘了这是一棵动态树, 每时每刻都是动态的. 小明要求你在这棵树上维护两种事件 事件0: 这棵树长出了一些果子, 即某个子树中的每个节点都会长出K个果子. 事件1: 小明希望你求出几条树枝上 ...
- BZOJ3589 动态树(树链剖分+容斥原理)
显然容斥后转化为求树链的交.这个题非常良心的保证了查询的路径都是到祖先的,求交就很休闲了. #include<iostream> #include<cstdio> #inclu ...
- bzoj千题计划214:bzoj3589: 动态树
http://www.lydsy.com/JudgeOnline/problem.php?id=3589 树链剖分 用线段数维护扫描线的方式来写,标记只打不下传 #include<cstdio& ...
- BZOJ3589 动态树[树剖/暴力/容斥]
操作0,显然直接线段树解决. 操作1,瓶颈在于重叠的链只算一次.在线段树上来看,如果一个区间被覆盖了,那么只算这个区间,子树里面也就不管了. 考虑对节点打标记来表示是否覆盖.但是,如果统一打完之后,并 ...
- bzoj3589 动态树 树链剖分+容斥
题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=3589 题解 事件 \(0\) 不需要说,直接做就可以了. 事件 \(1\) 的话,考虑如果直接 ...
- BZOJ3589动态树
**错误改了一上午. 先做熟练泼粪 k<=5,因此我们可以模拟这个过程,在线段树上把标记建出来然后pushup时候更新就好了. By:大奕哥 #include<bits/stdc++.h& ...
- 【BZOJ-3589】动态树 树链剖分 + 线段树 + 线段覆盖(特殊的技巧)
3589: 动态树 Time Limit: 30 Sec Memory Limit: 1024 MBSubmit: 405 Solved: 137[Submit][Status][Discuss] ...
- 【BZOJ3589】动态树 树链剖分+线段树
Description 别忘了这是一棵动态树, 每时每刻都是动态的. 小明要求你在这棵树上维护两种事件 事件0: 这棵树长出了一些果子, 即某个子树中的每个节点都会长出K个果子. 事件1: 小明希望你 ...
随机推荐
- Unix如何轻松快速复制
笔者在实践中总结了一套Unix操作系统硬盘的快速复制方法,成功地运用于建行几大Unix操作系统网络的建设中,收到了良好的效果.现将该方法介绍如下,供读者参考. 系统要求,两台主机软尽量相同.要求被复制 ...
- Centos优化Hadoop
导读 Hadoop是一个能够让用户轻松架构和使用的分布式计算平台,用户可以轻松地在Hadoop上开发和运行处理海量数据的应用程序,本节讲安装并且优化centos 6.7 系统下的Supper Hado ...
- [Educational Codeforces Round 16]E. Generate a String
[Educational Codeforces Round 16]E. Generate a String 试题描述 zscoder wants to generate an input file f ...
- 异常:The absolute uri: http://www.springframework.org/security/tags cannot be resolved in either web.xml or the jar files deployed with this application
The absolute uri: http://www.springframework.org/security/tags cannot be resolved in either web.xml ...
- Lucas的数论题解
Lucas的数论 reference 题目在这里> < Pre 数论分块 默认向下取整时. 形如\(\sum\limits_{i=1}^n f\left( \frac{n}{i}\righ ...
- 发个题目坑 二模03day1
1.数列(seq2.pas/c/cpp) 题目描述 一个数列定义如下:f(1) = 1,f(2) = 1,f(n) = (A * f(n - 1) + B * f(n - 2)) mod 7.给定 A ...
- (转载)【Android】ViewGroup全面分析
转载自:http://www.cnblogs.com/lqminn/archive/2013/01/23/2866543.html 一个Viewgroup基本的继承类格式如下: import andr ...
- 《转》IIS中配置通配符应用程序映射
本文转载自龚赤兵 电子工业出版社,如给您带来不便之处,请联系博主. eb开发新体验:ASP.NET 3.5 MVC架构与实战>第13章网站部署,本章主要实现了如何在IIS 6.0中一步一步地成功 ...
- vim技巧之快速进入引号删除至右引号前的内容
参考:http://blog.chinaunix.net/uid-23381466-id-88482.html f'l ct' #fX,X可用任何字符,l表示向右移一位,ct'表示删除至引号前di'
- codeforces 478B Random Teams 解题报告
题目链接:http://codeforces.com/problemset/problem/478/B 题目意思:有 n 个人,需要将这班人分成 m 个 组,每个组至少含有一个人,同一个组里的人两两可 ...