求出这棵树的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]网络的更多相关文章

  1. BZOJ4538 HNOI2016网络(树链剖分+线段树+堆/整体二分+树上差分)

    某两个点间的请求只对不在这条路径上的询问有影响.那么容易想到每次修改除该路径上的所有点的答案.对每个点建个两个堆,其中一个用来删除,线段树维护即可.由于一条路径在树剖后的dfs序中是log个区间,所以 ...

  2. 2019.01.13 bzoj4538: [Hnoi2016]网络(树链剖分)

    传送门 树链剖分一眼题. 题意简述: 给定一棵树,有三种操作: 加入一条路径 删除一条已加入的路径 询问不过一个点x的路径的最大值. 思路: 直接树链剖分维护答案. 因为询问的事不过点xxx的最大值, ...

  3. BZOJ4538:[HNOI2016]网络(树链剖分,堆)

    Description 一个简单的网络系统可以被描述成一棵无根树.每个节点为一个服务器.连接服务器与服务器的数据线则看做 一条树边.两个服务器进行数据的交互时,数据会经过连接这两个服务器的路径上的所有 ...

  4. 【BZOJ4538】[Hnoi2016]网络 整体二分+树状数组

    [BZOJ4538][Hnoi2016]网络 Description 一个简单的网络系统可以被描述成一棵无根树.每个节点为一个服务器.连接服务器与服务器的数据线则看做一条树边.两个服务器进行数据的交互 ...

  5. BZOJ 4538: [Hnoi2016]网络 [整体二分]

    4538: [Hnoi2016]网络 题意:一棵树,支持添加一条u到v权值为k的路径,删除之前的一条路径,询问不经过点x的路径的最大权值 考虑二分 整体二分最大权值,如果\(k \in [mid+1, ...

  6. 【LG3250】[HNOI2016]网络

    [LG3250][HNOI2016]网络 题面 洛谷 题解 30pts 对于\(m\leq 2000\),直接判断一下这个个点是否断掉一个交互,没断掉的里面取\(max\)即可,复杂度\(O(m^2\ ...

  7. 4538: [Hnoi2016]网络

    4538: [Hnoi2016]网络 链接 分析: 整体二分. 对于一次操作,可以二分一个答案mid,判断权值大于mid的路径是否全部经过这个点.如果是 ,那么这次询问的答案在[l,mid-1]之间, ...

  8. [HNOI2016]网络 树链剖分,堆

    [HNOI2016]网络 LG传送门 表示乱搞比正解难想. 整体二分很好想吧. 但是为了好写快乐,我们选择三个\(\log\)的乱搞. 先树剖,线段树套堆维护区间最大值.对于一次修改,如果是插入,就把 ...

  9. Luogu-3250 [HNOI2016]网络

    Luogu-3250 [HNOI2016]网络 题面 Luogu-3250 题解 CDQ分治...这个应该算是整体二分吧 二分重要度,按照时间从小到大加入大于重要度的边 对于一个询问,如果经过这个点的 ...

随机推荐

  1. java Unicode、ISO-8859-1、GBK、UTF-8编码转换深入浅出

    参考文献:搞懂ASCII, ISO8859-1, ANSI和Unicode Unicode百度文献 ISO-8859-1百度文献 注: 1.utf-8虽然是国际编码,对不同范围的字符使用不同长度的编码 ...

  2. Android ArrayAdapter使用

    1. 可以直接使用getContext()获取Context对象 2. 可以在构造方法中传入context, 数据对象的列表, super(context, 0, object);完成Adapter的 ...

  3. CocoaPods 安装

    虽然网上关于CocoaPods安装教程多不胜数,但是我在安装的过程中还是出现了很多错误,所以大家可以照下来步骤装一下,我相信会很好用. 前言 在iOS项目中使用第三方类库可以说是非常常见的事,但是要正 ...

  4. Memcached缓存在.Net 中的使用(memcacheddotnet)

    缓存对于提高大数据量的网站性能无疑不是一个很好的解决方案,针对缓存的使用网上同仁介绍很多,再次我仅仅分享一下自己对Memcached使用的简单介绍.Memchached的使用通过第三方DLL来完成,常 ...

  5. 【Java EE 学习 20】【使用过滤器实现登陆验证、权限认证】【观察者模式和监听器(使用监听器实现统计在线IP、登录IP 、踢人功能)】

    一.使用过滤器实现登录验证.权限认证 1.创建5张表 /*使用过滤器实现权限过滤功能*/ /**创建数据库*/ DROP DATABASE day20; CREATE DATABASE day20; ...

  6. macosx安装MySQLdb

    折腾了半天,记录一下. 先按照这个步骤安装mysql-python 如果python setup.py install 时候出现clang 错误,运行 python -E setup.py insta ...

  7. 百度编辑器UEditor ASP.NET示例Demo 分类: ASP.NET 2015-01-12 11:18 346人阅读 评论(0) 收藏

    在百度编辑器示例代码基础上进行了修改,封装成类库,只需简单配置即可使用. 完整demo下载 版权声明:本文为博主原创文章,未经博主允许不得转载.

  8. hdu 5437 优先队列+模拟 **

    比赛的时候虽然考虑到没门的情况,但是写了几组都能过,就没想了,23333,差一行代码就能A,遗憾~~ #include<cstdio> #include<iostream> # ...

  9. PMP 第六章 项目时间管理

    定义活动 排列活动顺序 估算活动资源 估算活动持续时间 制定进度计划 控制进度计划 1.进度管理计划和进度计划的内容分别是什么,有什么区别? 进度计划:项目各活动计划完成日期的编排.    进度管理计 ...

  10. linux中socket的理解

    对linux中socket的理解 一.socket 一般来说socket有一个别名也叫做套接字. socket起源于Unix,都可以用“打开open –> 读写write/read –> ...