博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
BZOJ3589 : 动态树
阅读量:7156 次
发布时间:2019-06-29

本文共 2723 字,大约阅读时间需要 9 分钟。

对于既要支持子树修改又要支持链查询,

需要树链剖分

然后求出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
#include
#define N 200010#define K 17using 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])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]
>1)+1; printf("%d\n",ans); }else{ read(x),read(y); add(1,1,n,st[x],en[x],y); } } return 0;}

  

 

转载地址:http://wehgl.baihongyu.com/

你可能感兴趣的文章
书荐——《微服务设计》(Sam Newman)
查看>>
PHP数组效率去重
查看>>
Google将要推出一个重新设计的Gmail界面
查看>>
yii2中like的查询
查看>>
gnu nano使用
查看>>
jquery给input框添加只读属性
查看>>
Ajax - Ajax, json, google maps api 遍历
查看>>
算法。
查看>>
Flex布局
查看>>
CAS单点登陆proxy代理实现
查看>>
由Android屏幕旋转说起
查看>>
2.3 Java的数组
查看>>
ubuntu 11.10 安装systemtap
查看>>
Django学习笔记(4)---ManyToMany 添加、删除关联、查询
查看>>
ORACLE----sql优化
查看>>
MyBatis3:SQL映射
查看>>
树的最小高度 Minimum Height Trees
查看>>
Socket简介
查看>>
Eclipse 新建Servlet出错问题
查看>>
eclipse问题
查看>>