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分治...这个应该算是整体二分吧 二分重要度,按照时间从小到大加入大于重要度的边 对于一个询问,如果经过这个点的 ...
随机推荐
- .pdb文件的使用方法
1.Demo1:用DLL_01生成my.dll.my.pdb.my.lib文件. 2.Demo2:在DLL_01_APP_02中使用DLL_01的dll. 步骤: 1.vs2008打开DLL_01_A ...
- PHP之MVC项目实战
本文主要包括以下内容 类文件自动加载 路径管理 页面跳转 注册自动加载方法 配置文件系统 cookie session 类文件自动加载 在PHP中使用别的类时,需要载入类文件,如果类很多的话,需要重复 ...
- php导出excel封装类
因为实际情况的需要,导出excel表格在后台开发的过程中会经常用到.下面是我在实际应用中自己整理的一个导出excel类,需要PHPExcel支持,本类很好的完成导出表格的基本样式,保存路径,切换工作薄 ...
- MyBatis魔法堂:即学即用篇
一.前言 本篇内容以理解MyBatis的基本用法和快速在项目中实践为目的,遵循Make it work,better and excellent原则. 技术栈为My ...
- 菜鸟学Linux命令:tar命令 压缩与解压缩
tar命令可以为linux的文件和目录创建档案.利用tar,可以为某一特定文件创建档案(备份文件),也可以在档案中改变文件,或者向档案中加入新的文件. tar最初被用来在磁带上创建档案,现在,用户可以 ...
- Yii 同域名的单点登录 SSO实现
SSO (Single Sign-on) 顾名思义就是几个子项目共用一个登录点. 原理简单来说就是服务端session 共享, 客户端跨域cookies. 实现非常简单,protected/confi ...
- 第十三篇:在SOUI中使用有窗口句柄的子窗口
前言: 无论一个DirectUI系统提供的DUI控件多么丰富,总会有些情况下用户需要在DUI窗口上放置有窗口句柄的子窗口. 为了和无窗口句柄的子窗口相区别,这里将有窗口句柄的子窗口称之为真窗口. 每一 ...
- 聊聊传统oo和js的某些对比——对象/函数/new关键字等
自己的学习记录,写的短点可以以后短时间内理清一些疑惑,看前要求你至少了解js中关于原型链等基本概念,因为文章直接以总结的形式理出知识点,没有去解释一些基本的概念! 1.1.熟记两句话,预预热 1. 函 ...
- SurfaceView
我们先来看下官方API对SurfaceView的介绍 SurfaceView的API介绍 Provides a dedicated drawing surface embedded inside of ...
- Excel动态合并行、合并列
背景: 在北京工作的时候,又一次同事问了我这样一个问题,说我要把从数据库获取到的数据直接通过NPOI进行导出,但是我对导出的格式要特殊的要求,如图: 冥思苦想,最终顺利帮同事解决问题,虽然有点瑕疵,但 ...