求出这棵树的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. XMPP框架下微信项目总结(2)授权登陆/注销/注册/打印日志

    xmpp授权登陆步骤1 初始化xmppstream 连接服务器 传递属性jid(IP地址 端口号)2 连接成功后 传递“登”陆密码授权 3 授权后,发送在线消息xmpp所有的代理都是子线程中调用的,处 ...

  2. Codeforces Round #344 (Div. 2)(按位或运算)

    Blake is a CEO of a large company called "Blake Technologies". He loves his company very m ...

  3. Swift - 语言指南,来自github学习

    @SwiftLanguage 更新于 2016-6-6,更新内容详见 Issue 55.往期更新回顾详见<收录周报> 这份指南汇集了 Swift 语言主流学习资源,并以开发者的视角整理编排 ...

  4. Android之WebView学习

    WebView常用方法 WebSettings 在使用WebView前我们都要进行相关的配置,常见的操作如下: WebSettings settings = mWebView.getSettings( ...

  5. 《linux系统及其编程》实验课记录(六)

    实验 6:Linux 文件系统 实验环境: 安装了 Red Hat Enterprise Linux 6.0 可运行系统,并且是成功验证系统.有另外一个无特权用户 student,密码 student ...

  6. 攻城狮在路上(贰) Spring(一)--- 软件环境、参考书目等一览表

    一.软件环境: 二.参考书目: <Spring 3.X 企业应用开发实战> 陈雄华.林开雄著 电子工业出版社出版 三.其他说明: spring 源码地址:https://github.co ...

  7. RAC NTP/CTSS

    本文總結主要參考: http://blog.itpub.net/23135684/viewspace-759693/ http://www.happyworld.net.cn/post/6.html ...

  8. java 杂物间 (一) Mybatis

    这里放置的是一些杂物,生人勿入. Token的一般parse 过程. @Test public void shouldDemonstrateGenericTokenReplacement() { Ge ...

  9. [JavaCore] 不错的Java基础学习资料-持续更新

    容易弄混的JAVA基础知识: http://www.iteye.com/topic/943647 [总结]String in Java: http://www.iteye.com/topic/5221 ...

  10. 网络模拟器WANem使用配置图文教程

    转自:http://blog.csdn.net/zm_21/article/details/25810263 WANem简介 由于公司在一些场合需要模拟真实的网络环境,如时延,丢包,抖动等,虽然使用L ...