BZOJ4538 : [Hnoi2016]网络
求出这棵树的dfs序,对于一条链$u-v$,假设$st[u]\leq st[v]$,那么一条链不经过点$x$当且仅当它满足下面任意一个条件:
1.$st[v]<st[x]$
2.$st[u]>en[x]$
3.$st[x]<st[lca(u,v)]\leq en[x]$
4.$st[u]<st[x],st[v]>en[x]$
前3种情况可以通过线段树做到$O(\log n)$修改,$O(\log n)$查询。
第4种情况可以通过kd-tree做到$O(\log n)$修改,$O(\sqrt{m})$查询。
总时间复杂度$O(m\sqrt{m})$。
#include<cstdio>
#include<queue>
#include<algorithm>
using namespace std;
typedef pair<int,int>P;
const int N=100010,M=200010;
int n,m,i,x,y,z,op[M][4],ans[M];
int g[N],v[M],nxt[M],ed,f[N],d[N],size[N],son[N],top[N],st[N],en[N],dfn;
int ex[M],val[N+M];priority_queue<P>S[N];
inline void read(int&a){char c;while(!(((c=getchar())>='0')&&(c<='9')));a=c-'0';while(((c=getchar())>='0')&&(c<='9'))(a*=10)+=c-'0';}
inline void add(int x,int y){v[++ed]=y;nxt[ed]=g[x];g[x]=ed;}
void dfs(int x){
size[x]=1;
for(int i=g[x];i;i=nxt[i])if(v[i]!=f[x]){
f[v[i]]=x,d[v[i]]=d[x]+1;
dfs(v[i]),size[x]+=size[v[i]];
if(size[v[i]]>size[son[x]])son[x]=v[i];
}
}
void dfs2(int x,int y){
st[x]=++dfn;top[x]=y;
if(son[x])dfs2(son[x],y);
for(int i=g[x];i;i=nxt[i])if(v[i]!=son[x]&&v[i]!=f[x])dfs2(v[i],v[i]);
en[x]=dfn;
}
inline int lca(int x,int y){
for(;top[x]!=top[y];x=f[top[x]])if(d[top[x]]<d[top[y]])swap(x,y);
return d[x]<d[y]?x:y;
}
inline void umax(int&a,int b){if(a<b)a=b;}
inline void umin(int&a,int b){if(a>b)a=b;}
inline int max(int a,int b){return a>b?a:b;}
void build(int x,int a,int b){
val[x]=-1;
if(a==b){
while(!S[a].empty())S[a].pop();
return;
}
int mid=(a+b)>>1;
build(x<<1,a,mid),build(x<<1|1,mid+1,b);
}
void ins(int x,int a,int b,int c,int p){
if(a==b){
ex[p]=1;
S[a].push(P(op[p][3],p));
while(!ex[S[a].top().second])S[a].pop();
val[x]=S[a].top().first;
return;
}
int mid=(a+b)>>1;
if(c<=mid)ins(x<<1,a,mid,c,p);else ins(x<<1|1,mid+1,b,c,p);
val[x]=max(val[x<<1],val[x<<1|1]);
}
void del(int x,int a,int b,int c,int p){
if(a==b){
ex[p]=0;
while(!S[a].empty()){
if(ex[S[a].top().second])break;
S[a].pop();
}
val[x]=S[a].empty()?-1:S[a].top().first;
return;
}
int mid=(a+b)>>1;
if(c<=mid)del(x<<1,a,mid,c,p);else del(x<<1|1,mid+1,b,c,p);
val[x]=max(val[x<<1],val[x<<1|1]);
}
void ask(int x,int a,int b,int c,int d,int&p){
if(c>d)return;
if(c<=a&&b<=d){umax(p,val[x]);return;}
int mid=(a+b)>>1;
if(c<=mid)ask(x<<1,a,mid,c,d,p);
if(d>mid)ask(x<<1|1,mid+1,b,c,d,p);
}
namespace KD{
int n,id[M],root,cmp_d,X,Y;
struct node{int d[2],l,r,Max[2],Min[2],v,mv,f;}T[M];
inline bool cmp(const node&a,const node&b){return a.d[cmp_d]<b.d[cmp_d];}
inline void up(int x){
if(T[x].l){
umax(T[x].Max[0],T[T[x].l].Max[0]);
umin(T[x].Min[0],T[T[x].l].Min[0]);
umax(T[x].Max[1],T[T[x].l].Max[1]);
umin(T[x].Min[1],T[T[x].l].Min[1]);
}
if(T[x].r){
umax(T[x].Max[0],T[T[x].r].Max[0]);
umin(T[x].Min[0],T[T[x].r].Min[0]);
umax(T[x].Max[1],T[T[x].r].Max[1]);
umin(T[x].Min[1],T[T[x].r].Min[1]);
}
}
int build(int l,int r,int D,int f){
int mid=(l+r)>>1;
cmp_d=D,nth_element(T+l+1,T+mid+1,T+r+1,cmp);
id[T[mid].f]=mid;
T[mid].f=f;
T[mid].Max[0]=T[mid].Min[0]=T[mid].d[0];
T[mid].Max[1]=T[mid].Min[1]=T[mid].d[1];
T[mid].v=T[mid].mv=-1;
if(l!=mid)T[mid].l=build(l,mid-1,!D,mid);
if(r!=mid)T[mid].r=build(mid+1,r,!D,mid);
return up(mid),mid;
}
inline void change(int x,int p){
for(T[x=id[x]].v=p;x;x=T[x].f){
T[x].mv=T[x].v;
if(T[x].l)umax(T[x].mv,T[T[x].l].mv);
if(T[x].r)umax(T[x].mv,T[T[x].r].mv);
}
}
void ask(int x,int&p){
if(T[x].mv<=p||T[x].Min[0]>=X||T[x].Max[1]<=Y)return;
if(T[x].Max[0]<X&&T[x].Min[1]>Y){p=T[x].mv;return;}
if(T[x].d[0]<X&&T[x].d[1]>Y&&p<T[x].v)p=T[x].v;
if(T[x].l)ask(T[x].l,p);
if(T[x].r)ask(T[x].r,p);
}
void solve(){
for(i=1;i<=m;i++)if(!op[i][0]){
n++;
x=st[op[i][1]],y=st[op[i][2]];
if(x>y)swap(x,y);
T[n].d[0]=x,T[n].d[1]=y,T[n].f=i;
}
root=build(1,n,0,0);
for(i=1;i<=m;i++){
if(!op[i][0])change(i,op[i][3]);
if(op[i][0]==1)change(op[i][1],-1);
if(op[i][0]==2)X=st[op[i][1]],Y=en[op[i][1]],ask(root,ans[i]);
}
}
}
int main(){
read(n),read(m);
for(i=1;i<n;i++)read(x),read(y),add(x,y),add(y,x);
dfs(1),dfs2(1,1);
for(i=1;i<=m;i++){
read(op[i][0]),read(op[i][1]);
if(!op[i][0])read(op[i][2]),read(op[i][3]);
ans[i]=-1;
}
build(1,1,n);
for(i=1;i<=m;i++){
x=op[i][1],y=op[i][2],z=op[i][3];
if(!op[i][0]){
x=st[x],y=st[y];
if(x>y)swap(x,y);
ins(1,1,n,y,i);
}
if(op[i][0]==1){
z=x;
x=st[op[z][1]],y=st[op[z][2]];
if(x>y)swap(x,y);
del(1,1,n,y,z);
}
if(op[i][0]==2)ask(1,1,n,1,st[x]-1,ans[i]);
}
build(1,1,n);
for(i=1;i<=m;i++){
x=op[i][1],y=op[i][2],z=op[i][3];
if(!op[i][0]){
x=st[x],y=st[y];
if(x>y)swap(x,y);
ins(1,1,n,x,i);
}
if(op[i][0]==1){
z=x;
x=st[op[z][1]],y=st[op[z][2]];
if(x>y)swap(x,y);
del(1,1,n,x,z);
}
if(op[i][0]==2)ask(1,1,n,en[x]+1,n,ans[i]);
}
build(1,1,n);
for(i=1;i<=m;i++){
x=op[i][1],y=op[i][2],z=op[i][3];
if(!op[i][0]){
x=st[lca(x,y)];
ins(1,1,n,x,i);
}
if(op[i][0]==1){
z=x;
x=st[lca(op[z][1],op[z][2])];
del(1,1,n,x,z);
}
if(op[i][0]==2)ask(1,1,n,st[x]+1,en[x],ans[i]);
}
KD::solve();
for(i=1;i<=m;i++)if(op[i][0]==2)printf("%d\n",ans[i]);
return 0;
}
BZOJ4538 : [Hnoi2016]网络的更多相关文章
- BZOJ4538 HNOI2016网络(树链剖分+线段树+堆/整体二分+树上差分)
某两个点间的请求只对不在这条路径上的询问有影响.那么容易想到每次修改除该路径上的所有点的答案.对每个点建个两个堆,其中一个用来删除,线段树维护即可.由于一条路径在树剖后的dfs序中是log个区间,所以 ...
- 2019.01.13 bzoj4538: [Hnoi2016]网络(树链剖分)
传送门 树链剖分一眼题. 题意简述: 给定一棵树,有三种操作: 加入一条路径 删除一条已加入的路径 询问不过一个点x的路径的最大值. 思路: 直接树链剖分维护答案. 因为询问的事不过点xxx的最大值, ...
- BZOJ4538:[HNOI2016]网络(树链剖分,堆)
Description 一个简单的网络系统可以被描述成一棵无根树.每个节点为一个服务器.连接服务器与服务器的数据线则看做 一条树边.两个服务器进行数据的交互时,数据会经过连接这两个服务器的路径上的所有 ...
- 【BZOJ4538】[Hnoi2016]网络 整体二分+树状数组
[BZOJ4538][Hnoi2016]网络 Description 一个简单的网络系统可以被描述成一棵无根树.每个节点为一个服务器.连接服务器与服务器的数据线则看做一条树边.两个服务器进行数据的交互 ...
- BZOJ 4538: [Hnoi2016]网络 [整体二分]
4538: [Hnoi2016]网络 题意:一棵树,支持添加一条u到v权值为k的路径,删除之前的一条路径,询问不经过点x的路径的最大权值 考虑二分 整体二分最大权值,如果\(k \in [mid+1, ...
- 【LG3250】[HNOI2016]网络
[LG3250][HNOI2016]网络 题面 洛谷 题解 30pts 对于\(m\leq 2000\),直接判断一下这个个点是否断掉一个交互,没断掉的里面取\(max\)即可,复杂度\(O(m^2\ ...
- 4538: [Hnoi2016]网络
4538: [Hnoi2016]网络 链接 分析: 整体二分. 对于一次操作,可以二分一个答案mid,判断权值大于mid的路径是否全部经过这个点.如果是 ,那么这次询问的答案在[l,mid-1]之间, ...
- [HNOI2016]网络 树链剖分,堆
[HNOI2016]网络 LG传送门 表示乱搞比正解难想. 整体二分很好想吧. 但是为了好写快乐,我们选择三个\(\log\)的乱搞. 先树剖,线段树套堆维护区间最大值.对于一次修改,如果是插入,就把 ...
- Luogu-3250 [HNOI2016]网络
Luogu-3250 [HNOI2016]网络 题面 Luogu-3250 题解 CDQ分治...这个应该算是整体二分吧 二分重要度,按照时间从小到大加入大于重要度的边 对于一个询问,如果经过这个点的 ...
随机推荐
- Android接口传递Json数组的处理方式
public static XTResult<Void> addTravel(String uuid, String travelName, String travelId, String ...
- postgresql导入及导出
导入命令 psql -d GAME -U postgres -f /root/plubic.sql 出现如下错误: psql: FATAL: Peer authentication failed f ...
- Android View -- setTranslationX
通过此方法使View位置发生偏移,达到margin的作用却又不改变View的getLeft()的值. 恢复方法是setTranslationX(0),而不是上一次偏移量的相反数. 不过,通过getLo ...
- PHP define()的用法
define()函数理解1(着重于作用的理解) define() 函数定义一个常量. 常量的特点: 常量类似变量,不同之处在于:在设定以后,常量的值无法更改常量名,不需要开头的美元符号 ($),作用域 ...
- OCJP(1Z0-851) 模拟题分析(四)over
Exam : 1Z0-851 Java Standard Edition 6 Programmer Certified Professional Exam 以下分析全都是我自己分析或者参考网上的,定有 ...
- rhel7初体验
Redhat7界面明显比之前的版本华丽了不少,貌似Redhat对普通用户的使用也要进行普及 可以在安装的同时修改root密码和创建新用户
- GMap.Net开发之地址解析与路径查找
上一篇介绍了如何在GMap地图上添加多边形,这篇介绍下如何使用在线的地图服务进行“地址解析”和“路径查找”. 先看地址解析,GMap中的地址解析主要用到GeocodingProvider中的如下方法: ...
- 攻城狮在路上(叁)Linux(十一)--- 用户与用户组、文件权限、目录配置
一.用户与用户组: 3个概念:文件所有者(user).用户组(group).其他人(others). /etc/passwd <==存放所有的用户名 /etc/shadow <==存放 ...
- bbed的使用--查看数据文件信息 & sid信息
1.得到文件的块大小和数据块个数 在Linux和Unix上,oracle提供了一个小工具dbfsize用于查看文件块大小 (可以参看[ID:360032.1]How to detect and fix ...
- ubuntu kylin中如何截图
windows操作系统中,我通常使用的截图工具是QQ的“ctrl+alt+a”快捷键.但是在ubuntu中,linux qq常年不更新,我也就彻底放弃了使用了,反正ubuntu通常只是拿来开发.其实没 ...