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分治...这个应该算是整体二分吧 二分重要度,按照时间从小到大加入大于重要度的边 对于一个询问,如果经过这个点的 ...
随机推荐
- springmvc注解配置
<?xml version="1.0" encoding="UTF-8" ?> <beans xmlns="http://www.s ...
- myaql常用函数
一.数学函数 abs(x) 返回x的绝对值 bin(x) 返回x的二进制(oct返回八进制,hex返回十六进制) ceiling(x) 返回大于x的最小整数值 exp(x) 返回值e( ...
- EF – 3.EF数据查询基础(下)数据关联
5.5.1 <关于“数据关联”,你不一定清楚的事> 这讲视频比较全面地介绍了“一对一”.“一对多”和“多对多”三种数据关联类型在关系数据库和Entity Framework数据模型中的实现 ...
- 7z命令行工具
7z (中文)是优秀开源的压缩解压缩软件(wiki: en 中文),有windows版本与linux版本,最新的9.32版本支持的格式包括: 压缩与解压缩均支持:7z, XZ, BZIP2, GZI ...
- NPOI读写Excel
1.整个Excel表格叫做工作表:WorkBook(工作薄),包含的叫页(工作表):Sheet:行:Row:单元格Cell. 2.NPOI是POI的C#版本,NPOI的行和列的index都是从0开始 ...
- MDX语法之排序函数Order
使用场景: 排列指定集的成员,可以选择保留或打乱原有的层次结构. 语法: Numeric expression syntax Order(Set_Expression, Numeric_Express ...
- WPF Navigation
在开始学习WPF时,一开始对WPF的Window, Page, UserControl感到很迷惑.不知道什么时候该使用哪一个.下面简单介绍一下这三者的区别. Window:故名思意,桌面程序的窗体.在 ...
- Mysql数据库操作系统及配置参数优化
数据库结构优化 表的水平拆分常用的水平拆分方法为:1.对 customer_id进行 hash运算,如果要拆分成5个表 则使用mod(customer_id,5)取出0-4个值2.针对不同的 hash ...
- VS2010和matlab2010混合编程中char16_t重定义的问题
原因是VS2010中的yvals.h添加了char16_t的定义,而Matlab的matrix.h也包含对char16_t的定义,所以同时包含这两个头文件的话,会导致重复定义char16_t的错误.只 ...
- ASP.NET 4.0 取消表单危险字符验证
/// <summary> /// ASP.NET4.0 表单验证类 /// </summary> public class FormRequestValidation : R ...