HNOI2016 网络 (BZOJ4538)

HNOI2016 Day1 T2 网络

题意:给定一棵树,然后有若干个操作,可以新添加一条从u到v的权值为w的路径,或者将之前的一条路径删掉,动态询问不经过某个点的路径的最大权值

正解:树链剖分+线段树+堆

考场上面打了一个裸裸的树链剖分,连线段树都没套,复杂度是O(m^2 logn)的。当时真是傻了,只要套一个堆就可以AC了。。。我真傻,真的

首先考虑先树链剖分,然后看怎么处理这三个操作

显然题目要求我们动态维护不经过一个点的最大路径权值,那么我们就考虑用堆

每个线段树的结点里面存两个堆,都是大根堆,分别维护所有的入过堆的元素和已经被删除的元素,当我们需要求堆顶元素时,只需看一下两个堆的堆顶元素是否相等,相等的话顺便同时删掉,直到找到一个不相等的或者堆为空,就返回堆顶元素。这样就可以避免了如何删除路径的尴尬问题。

接着当我们插入路径的时候,显然树链剖分沿着重链往上跳的时候可以把经过的连续路径存下来。然后我们对于这些路径取反,把取反后的路径(即跳的过程中没有经过的点集或线段集)他们的线段树的堆中加入当前需要插入路径的权值。如果是删除的话,往删除堆里加入元素就可以了。

至于查询,就是找到之后一路往上跳,然后取一个MAX就可以了(找不到返回-1)。

  1 //It is made by jump~
  2 #include <iostream>
  3 #include <cstdlib>
  4 #include <cstring>
  5 #include <cstdio>
  6 #include <cmath>
  7 #include <algorithm>
  8 #include <vector>
  9 #include <queue>
 10 #include <map>
 11 using namespace std;
 12 typedef long long LL;
 13 const int MAXN = 100011;
 14 const int MAXM = 400011;
 15 int n,m;
 16 int first[MAXN],next[MAXN*2],to[MAXN*2];
 17 int ecnt;
 18 int q1[MAXM],q2[MAXM],q3[MAXM];
 19
 20 int father[MAXN],top[MAXN],pson[MAXN],siz[MAXN],id[MAXN],deep[MAXN];
 21
 22 //树链剖分+ 线段树维护堆
 23
 24 struct qqueue{
 25     priority_queue<int>a,b;
 26     void push(int x) { a.push(x); }
 27     void del(int x) { b.push(x); }
 28     int top(){
 29     while(!b.empty() && a.top()==b.top()) a.pop(),b.pop();
 30     if(a.empty()) return -1;
 31     return a.top();
 32     }
 33 }jump[MAXN*4];
 34
 35 struct E{
 36     int l,r;
 37 }line[MAXM];//维护线段取反后的两个端点
 38
 39 inline int getint()
 40 {
 41        int w=0,q=0;
 42        char c=getchar();
 43        while((c<‘0‘ || c>‘9‘) && c!=‘-‘) c=getchar();
 44        if (c==‘-‘)  q=1, c=getchar();
 45        while (c>=‘0‘ && c<=‘9‘) w=w*10+c-‘0‘, c=getchar();
 46        return q ? -w : w;
 47 }
 48
 49 inline void link(int x,int y){
 50     next[++ecnt]=first[x]; first[x]=ecnt; to[ecnt]=y;
 51     next[++ecnt]=first[y]; first[y]=ecnt; to[ecnt]=x;
 52 }
 53
 54 inline void dfs1(int x,int fa){
 55     siz[x]=1;
 56     for(int i=first[x];i;i=next[i]) {
 57     int v=to[i];
 58     if(v==fa) continue;
 59     father[v]=x; deep[v]=deep[x]+1; dfs1(v,x);
 60     siz[x]+=siz[v]; if(siz[v]>siz[pson[x]]) pson[x]=v;
 61     }
 62 }
 63
 64 inline void dfs2(int x,int fa){
 65     id[x]=++ecnt;
 66     if(pson[x]) top[pson[x]]=top[x],dfs2(pson[x],x);
 67     for(int i=first[x];i;i=next[i]) {
 68     int v=to[i];
 69     if(v==fa || v==pson[x]) continue;
 70     top[v]=v;
 71     dfs2(v,x);
 72     }
 73 }
 74
 75 bool cmp(E q,E qq) { if(q.l==qq.l) return q.r<qq.r;  return q.l<qq.l; }
 76
 77 inline void geng(int root,int l,int r,int ql,int qr,int val,int type){
 78     if(ql>qr) return ;
 79     if(ql==l && qr==r) {
 80     if(type==1) jump[root].push(val);
 81     else jump[root].del(val);
 82     return ;
 83     }
 84     int mid=l+(r-l)/2; int lc=root*2,rc=lc+1;
 85     if(ql<=mid) geng(lc,l,mid,ql,min(qr,mid),val,type);
 86     if(qr>mid) geng(rc,mid+1,r,max(ql,mid+1),qr,val,type);
 87 }
 88
 89 inline void update(int x,int y,int z,int type){
 90     int f1=top[x],f2=top[y];
 91     ecnt=0;
 92     while(f1!=f2) {
 93     if(deep[f1]<deep[f2]) swap(x,y),swap(f1,f2);
 94     line[++ecnt].l=id[f1]; line[ecnt].r=id[x];
 95     x=father[f1]; f1=top[x];
 96     }
 97     if(deep[x]<deep[y]) swap(x,y);
 98     line[++ecnt].l=id[y]; line[ecnt].r=id[x];
 99
100     sort(line+1,line+ecnt+1,cmp);
101     int nowl=1;
102     for(int i=1;i<=ecnt;i++) {
103     geng(1,1,n,nowl,line[i].l-1,z,type);
104     nowl=line[i].r+1;
105     }
106     geng(1,1,n,nowl,n,z,type);
107 }
108
109 inline int query(int root,int l,int r,int x){
110     if(l==r) return jump[root].top();
111     int mid=l+(r-l)/2; int lc=root*2,rc=lc+1;
112     if(x<=mid) return max(jump[root].top(),query(lc,l,mid,x));
113     else return max(jump[root].top(),query(rc,mid+1,r,x));
114 }
115
116 inline void solve(){
117     for(int i=1;i<=n;i++) top[i]=1;
118     for(int i=1;i<=n;i++) siz[i]=n-i+1;
119     for(int i=1;i<=n-1;i++) pson[i]=i+1;
120     for(int i=1;i<=n;i++) deep[i]=id[i]=i;
121     for(int i=2;i<=n;i++) father[i]=i-1;
122 }
123
124 int main()
125 {
126   n=getint();m=getint();
127   int x,y,type;
128   for(int i=1;i<n;i++) {
129       x=getint(),y=getint();
130       link(x,y);
131   }
132
133   if(to[first[1]]==2) solve();
134
135   deep[1]=1; dfs1(1,0);
136   top[1]=1; ecnt=0; dfs2(1,0);
137
138   for(int i=1;i<=m;i++) {
139       type=getint();
140       if(type==0) {
141       q1[i]=getint(); q2[i]=getint(); q3[i]=getint();
142       update(q1[i],q2[i],q3[i],1);
143       }
144       else if(type==1) {
145       q1[i]=getint();
146       update(q1[q1[i]],q2[q1[i]],q3[q1[i]],0);
147       }
148       else {
149       q1[i]=getint();
150       printf("%d\n",query(1,1,n,id[ q1[i] ]));
151       }
152   }
153   return 0;
154 }
时间: 2024-11-06 07:09:47

HNOI2016 网络 (BZOJ4538)的相关文章

【bzoj】4538: [Hnoi2016]网络

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=4538 维护一个数据结构支持对于一颗树的操作,需要支持: 1.对于树上的一条路径上的每个点上放一个值. 2.撤销某次操作的路劲放. 3.查询除了经过这个点的路径的最大值. 往一个路径上丢值相当于往不经过条路径的所有点上丢值. 用一个树链剖分即可维护,对于操作区间取反. 直接查询单点最大值即可. 为了维护单点最大值,线段树中的每一个点对应两个堆,用于维护插入誉删除. 防止爆空间,所以标记永久

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)$修改,$

bzoj 4538: [Hnoi2016]网络

Description 一个简单的网络系统可以被描述成一棵无根树.每个节点为一个服务器.连接服务器与服务器的数据线则看做一条树边.两个服务器进行数据的交互时,数据会经过连接这两个服务器的路径上的所有服务器(包括这两个服务器自身).由于这条路径是唯一的,当路径上的某个服务器出现故障,无法正常运行时,数据便无法交互.此外,每个数据交互请求都有一个重要度,越重要的请求显然需要得到越高的优先处理权.现在,你作为一个网络系统的管理员,要监控整个系统的运行状态.系统的运行也是很简单的,在每一个时刻,只有可能

4538: [Hnoi2016]网络 链剖 + 堆(优先队列) / 整体二分

GDOI之后写的第一道题.看到之后没什么感觉(是我太弱,中途一度想用kpm之前在某道题上用过的链表的方法.想了想应该不可能.) 好!让我们来分析这道题吧!首先简化模型,它是要求维护树上的一些路径,支持添加和修改,要求不经过某个点的路径的最大权值(不经过某个点,我一度想到了动点分,虽然我还不会). 我们可以先考虑在链上(其实仔细一想,如果链上的你会做,那么树上的大多数情况下便是多个了链剖而已吧!)的情况.在链上,有一些区间覆盖,要求没有覆盖某个点的区间的最大权值.那么我们接着想如果询问2询问了一个

[HNOI2016]网络

题目描述 一个简单的网络系统可以被描述成一棵无根树.每个节点为一个服务器.连接服务器与服务器的数据线则看做一条树边.两个服务器进行数据的交互时,数据会经过连接这两个服务器的路径上的所有服务器(包括这两个服务器自身). 由于这条路径是唯一的,当路径上的某个服务器出现故障,无法正常运行时,数据便无法交互.此外,每个数据交互请求都有一个重要度,越重要的请求显然需要得到越高的优先处理权.现在,你作为一个网络系统的管理员,要监控整个系统的运行状态.系统的运行也是很简单的,在每一个时刻,只有可能出现下列三种

数据结构(树链剖分,堆):HNOI 2016 network

2215. [HNOI2016]网络 ★★★☆   输入文件:network_tenderRun.in   输出文件:network_tenderRun.out   简单对比时间限制:2 s   内存限制:128 MB [题目描述] [输入格式] [输出格式] [样例输入1] 13 23 1 2 1 3 2 4 2 5 3 6 3 7 4 8 4 9 6 10 6 11 7 12 7 13 2 1 0 8 13 3 0 9 12 5 2 9 2 8 2 2 0 10 12 1 2 2 1 3 2

树套树乱讲

树套树乱讲 树状数组套线段树 先学会主席树. 主席树可以被理解为一个二维平面,其中n棵树可以视作横轴,每棵树中的坐标范围(也就是线段树的坐标范围)可以视作纵轴.这样一来就是用主席树维护了一些在二维平面上的点,给定\(a,b,c,d\),可以在\(O(\log{n})\)的时间内求出满足\(a\le x_i\le b,c\le y_i\le d\)的\(i\)的数量. 而树状数组套线段树就是把这个问题动态化. 对于上述的问题,我们是通过对主席树直接维护前缀和,查询时两棵主席树相减,再在区间\([c

树套树乱讲的代码

树套树乱讲的代码 由于部分代码的完成时间较早所以码风可能有些差异,敬请谅解. 动态区间Kth 题面 整体二分题解 #include<cstdio> #include<cstring> #include<cmath> #include<iostream> #include<algorithm> using namespace std; const int N=10005; struct segment_tree{int v;int ls,rs;}t

[BZOJ4538]网络

本来想用树剖艹,然而并不会卡常数这种神奇的技能,,,于是还是乖乖写正解吧QAQ 我们可以把一个询问转化为二分判定性问题 二分答案$K$,若所有权值大于$K$的路径都经过询问点$x$,则答案比$K$小,否则答案比$K$大 对于多组询问,外层再套一个整体二分就行了 至于判断有几条路径经过点$x$,对于一条路径$(u,v)$我们把$u$和$v$置为$1$,$lca(u,v)$和$lca(u,v)$的父亲置为$-1$,这样经过一个节点$x$的路径条数就是以其为根的子树的标记和,,, 由于子树区间求和有关