bzoj3545 && bzoj3551 Peaks(离线版&&在线版)

题目给n点m边的无向图,有点权和边权

每次询问求点v在经过路径上的边都不超过w的情况下,能到达的第k大的点的权值

首先离线版比较容易想到,属于我现在能码出来的最难的码农题之一吧T T

这道题思路是这样的

1、对于边权的限制条件,可以先想到做一棵最小生成树

2、对于第k大这种询问,可以建权值线段树,但是山的高度太大到1e9,所以我们还要先离散化到1e6的水平才能用线段树

3、显然不能对每个询问w都建线段树,因此要用到主席树。具体做法是将询问和边权都排序(详情看代码),给每个点建一棵线段树,然后边建mst边回答询问,每次合并两个连通块的时候,要将两个连通块的线段树合并起来,线段树支持区间加减的优势就出来了

离线的做法是这样的,代码也挺好写

然后再来考虑在线怎么做= =

题解的做法很神,很难想到

同样是建最小生成树,不过做了变形

比如每次连边有 x=find(e[i].from), y=find(e[i].to);

这时候新建一个节点z,点权是边权

然后fa[x]=fa[y]=z,即新建的节点是此连通块的根

这样做有什么用呢。。好处就是建完树后,所有的MST的节点都在叶子节点,上边的全是由边转化的点

而且由kruskal的过程可知,越晚加入的边,边权越大,因此在新树中,除了叶子节点,越往上点的权值越大

这一点就可以被每次询问的边权不超过w所用,此时w只要从询问的v开始,倍增往上找到第一个边权大于它的点

一开始还要求出此树的dfs序:叶子节点仅保留一次,非叶子节点(即边的节点)保留low和high

然后建主席树,仅叶子节点要修改权值线段树,否则不进行修改,将上棵树的根复制过来

询问的时候,找到第一个大于w的点v,利用low[v]和high[v]这两个根的线段树,减一减就是v在不超过w的情况下能走到的点的权值

然后找就是了

离线:

 1 #include<stdio.h>
 2 #include<string.h>
 3 #include<algorithm>
 4 using namespace std;
 5 const int maxn = 100002;
 6 struct node{
 7     int u,v,w,id;
 8     bool q;
 9 }e[maxn*10];
10 int n,m,T,N,ls[maxn*50],rs[maxn*50],sum[maxn*50],tot,h[maxn],ori[maxn],a[maxn],root[maxn],fa[maxn],ans[maxn*5];
11
12 void read(int &x){
13     x=0; int f=1; char c=getchar();
14     while (c<‘0‘ || c>‘9‘){if (c==‘-‘) f=-1; c=getchar();}
15     while (c>=‘0‘ && c<=‘9‘) x=x*10+c-48,c=getchar();
16     x*=f;
17 }
18
19 bool operator<(node a, node b){
20     return a.w==b.w?a.q<b.q:a.w<b.w;
21 }
22
23 int find(int x){
24     return fa[x]==x?x:fa[x]=find(fa[x]);
25 }
26
27 void insert(int &x, int l, int r, int pos){
28     if (!x) x=++tot;
29     if (l==r){
30         sum[x]=1;
31         return;
32     }
33     int mid=l+r>>1;
34     if (pos<=mid) insert(ls[x],l,mid,pos);
35     else insert(rs[x],mid+1,r,pos);
36     sum[x]=sum[ls[x]]+sum[rs[x]];
37 }
38
39 int merge(int x, int y){
40     if (!x || !y) return x+y;
41     if (!ls[x] && !rs[x]){
42         sum[x]+=sum[y];
43         return x;
44     }
45     ls[x]=merge(ls[x],ls[y]);
46     rs[x]=merge(rs[x],rs[y]);
47     sum[x]=sum[ls[x]]+sum[rs[x]];
48     return x;
49 }
50
51 int query(int x, int l, int r, int pos){
52     if (l==r) return l; int mid=l+r>>1;
53     if (sum[ls[x]]>=pos) return query(ls[x],l,mid,pos);
54     else return query(rs[x],mid+1,r,pos-sum[ls[x]]);
55 }
56
57 int main(){
58     read(n); read(m); read(T);
59     for (int i=1; i<=n; i++) read(h[i]), a[i]=h[i];
60     sort(a+1,a+1+n); N=unique(a+1,a+1+n)-a-1;
61     for (int i=1,height; i<=n; i++) height=h[i],h[i]=lower_bound(a+1,a+1+N,h[i])-a,ori[h[i]]=height;
62     for (int i=1; i<=n; i++) insert(root[i],1,n,h[i]),fa[i]=i;
63     for (int i=1; i<=m; i++) read(e[i].u), read(e[i].v), read(e[i].w), e[i].q=0;
64     for (int i=1+m; i<=T+m; i++) read(e[i].u), read(e[i].w), read(e[i].v), e[i].q=1, e[i].id=i-m;
65     sort(e+1,e+1+m+T);
66     for (int i=1,cnt=0,u,v; i<=m+T; i++){
67         if (!e[i].q){
68             if (cnt==n-1) continue;
69             u=find(e[i].u), v=find(e[i].v);
70             if (u!=v){
71                 fa[u]=v; cnt++;
72                 root[v]=merge(root[u],root[v]);
73             }
74         }
75         else{
76             int x=find(e[i].u);
77             if (sum[root[x]]<e[i].v) ans[e[i].id]=-1;
78             else ans[e[i].id]=ori[query(root[x],1,n,sum[root[x]]-e[i].v+1)];
79         }
80     }
81     for (int i=1; i<=T; i++) printf("%d\n", ans[i]);
82     return 0;
83 }

在线:

  1 #include<stdio.h>
  2 #include<string.h>
  3 #include<algorithm>
  4 using namespace std;
  5 const int logn = 17, maxn = 200005;
  6 struct node{
  7     int to,next;
  8 }e[maxn];
  9 struct data{
 10     int u,v,w;
 11 }E[maxn*3];
 12 int n,m,T,tot,cnt,ans,head[maxn],f[maxn],fa[maxn][logn+1],dep[maxn],mx[maxn][logn+1];
 13 int N,h[maxn],orz[maxn],a[maxn],top,low[maxn],high[maxn],root[maxn*2],st[maxn*2];
 14 int ls[5000005],rs[5000005],sum[5000005];
 15
 16 void read(int &x){
 17     x=0; char c=getchar(); int f=1;
 18     while (c<‘0‘ || c>‘9‘){if (c==‘-‘) f=-1; c=getchar();}
 19     while (c>=‘0‘ && c<=‘9‘) x=x*10+c-48, c=getchar();
 20     x*=f;
 21 }
 22 bool operator<(data a, data b){return a.w<b.w;}
 23 void insert(int u, int v){e[++tot].to=v; e[tot].next=head[u]; head[u]=tot;}
 24 int find(int x){return f[x]==x?x:f[x]=find(f[x]);}
 25
 26 int getrt(int u, int val){
 27     for (int i=logn; i>=0; i--)
 28         if (dep[u]>(1<<i) && mx[u][i]<=val) u=fa[u][i];
 29     return u;
 30 }
 31
 32 void dfs(int u){
 33     st[++top]=u; dep[u]=dep[fa[u][0]]+1;
 34     if (u>n) low[u]=top;
 35     for (int i=1; i<=logn; i++) fa[u][i]=fa[fa[u][i-1]][i-1];
 36     for (int i=1; i<=logn; i++) mx[u][i]=max(mx[u][i-1],mx[fa[u][i-1]][i-1]);
 37     for (int i=head[u],v; i; i=e[i].next) fa[v=e[i].to][0]=u,mx[v][0]=h[u],dfs(v);
 38     if (u>n) st[++top]=u,high[u]=top;
 39 }
 40
 41 void update(int &x, int l, int r, int last, int pos){
 42     x=++cnt;  //注意这里千万不要if(!x)
 43     sum[x]=sum[last]+1;
 44     if (l==r) return; else ls[x]=ls[last],rs[x]=rs[last];
 45     int mid=l+r>>1;
 46     if (pos<=mid) update(ls[x],l,mid,ls[last],pos);
 47     else update(rs[x],mid+1,r,rs[last],pos);
 48 }
 49
 50 int query(int l, int r, int x, int y, int rk){
 51     if (l==r) return l;
 52     int mid=l+r>>1,s=sum[ls[y]]-sum[ls[x]];  //注意是  左子树的sum差
 53     if (s>=rk) return query(l,mid,ls[x],ls[y],rk);
 54     else return query(mid+1,r,rs[x],rs[y],rk-s);
 55 }
 56
 57 void build(){
 58     for (int i=1; i<=m; i++) read(E[i].u),read(E[i].v),read(E[i].w);
 59     sort(E+1,E+1+m);
 60     N=n; tot=1; cnt=0;
 61     for (int i=1; i<=2*n; i++) f[i]=i;
 62     for (int i=1,tmp; i<=m; i++){
 63         int u=find(E[i].u), v=find(E[i].v);
 64         if (u!=v){
 65             tmp=++N;
 66             f[u]=f[v]=tmp; h[tmp]=E[i].w;
 67             insert(tmp,v); insert(tmp,u);
 68             if (N==2*n-1) break;
 69         }
 70     }
 71     for (int i=1; i<=n; i++) if (!dep[i]) dfs(find(i));
 72     for (int i=1,x; i<=top; i++){
 73         x=st[i];
 74         if (x<=n) update(root[i],1,n,root[i-1],h[x]);
 75         else root[i]=root[i-1];
 76     }
 77 }
 78
 79 void solve(){
 80     while (T--){
 81         int v,x,k,t,a,b,tot;
 82         read(v); read(x); read(k);
 83         if (ans!=-1) v^=ans,x^=ans,k^=ans;
 84         t=getrt(v,x);
 85         a=low[t]; b=high[t];
 86         if ((tot=sum[root[b]]-sum[root[a]])<k) printf("%d\n", ans=-1);
 87         else printf("%d\n", ans=orz[query(1,n,root[a],root[b],tot-k+1)]);
 88     }
 89 }
 90
 91 void pre(){
 92     read(n); read(m); read(T);
 93     for (int i=1; i<=n; i++) read(h[i]),a[i]=h[i];
 94     sort(a+1,a+1+n); N=unique(a+1,a+1+n)-a-1;
 95     for (int i=1,height; i<=n; i++) height=h[i],h[i]=lower_bound(a+1,a+1+N,h[i])-a,orz[h[i]]=height;
 96 }
 97
 98 int main(){
 99     pre();
100     build();
101     solve();
102     return 0;
103 }

时间: 2024-10-09 22:16:29

bzoj3545 && bzoj3551 Peaks(离线版&&在线版)的相关文章

Visual Studio 2015和.Net 2015 预览版在线安装和ISO镜像安装光盘下载

Visual Studio 2015和.Net 2015 预览版在线安装和ISO镜像安装光盘下载 微软刚刚宣布了 Visual Studio 2015和.Net 2015 预览版,并同时提供了下载. 微软在纽约正进行中的#Connect# 全球开发者在线大会上宣布了Visual Studio 2015 和.NET 2015预览版,将为开发者提供构建跨多个平台应用程序的新功能,包括从Windows 到 Linux 到iOS,是的,以及到Android. 微软MSDN介绍称,目前移动开发者需要面对A

时尚版在线Word文本转皮肤转换器

假如我们能够将PDF文件转换成为更常见的图片格式,那么就可以在无需安装额外PDF阅读工具的情况下 ,轻松打开并阅读其中的内容了. 从网络上下载的普通PDF转换成Word转换器,这部分PDF转换器本身的功能非常单一,尤其是针对PDF文件 内容的识别技术相对落后,因此其实际转换的效果并不出色.甚至在某些情况下,由于软件本身解析技 术上的落后,还很有可能出现转换之后的Word文件内容乱码的情况发生. 图文混合PDF如何转换成Word是考验PDF转换器功能的一个关卡.优秀的PDF转换成Word转换器其核

2018最新微信运动刷步数教程,网页版在线刷步秒上万

随着移动互联网的普及,现在手机微信应用也越来越被依赖,说到微信那就不得不说其中的一项互动功能-"微信运动".他不仅可以记录你当天的运动量,还可以与好友来一场"激烈"的PK以争夺唯一的运动封面展示权,但是问题又来了,如果我们每天上班没办法也没时间走那么多步数,难道我们就只能被沦为loser了吗? 答案肯定是否定的,今天我们就来介绍一个微信运动刷步数的小工具,让你躺在床上即可打败那些日行十公里的好友们.(当然刷步数只是为了娱乐,真正身体才是自己的,要想有一副强健的体魄还

[您有新的未分配科技点][BZOJ3545&amp;BZOJ3551]克鲁斯卡尔重构树

这次我们来搞一个很新奇的知识点:克鲁斯卡尔重构树.它也是一种图,是克鲁斯卡尔算法求最小生成树的升级版首先看下面一个问题:BZOJ3545 Peaks. 在Bytemountains有N座山峰,每座山峰有他的高度h_i.有些山峰之间有双向道路相连,共M条路径,每条路径有一个困难值,这个值越大表示越难走. 现在有Q组询问,每组询问询问从点v开始只经过困难值小于等于x的路径所能到达的山峰中第k高的山峰,如果无解输出-1.N<=1e5,M,Q<=5*1e5 上面这个题没有要求在线,因此我们可以离线构造

InstallShield12豪华版破解版下载|InstallShield下载|软件打包工具

InstallShield 12 豪华版+破解版 下载 下载速度:220kb/s InstallShield 12为软件发行方提供率先的安装程序解决方式,可以制作强大可靠的Windows Installer(MSI).InstallScript以及跨平台的安装程序.它是最著名的专业安装程序制作软件,如今Macrovision公司和InstallShield公司合并,该Premier Edition豪华版包括了InstallShield 12.0 Professional Edition:Inst

【电脑城热销】深度技术 Ghost Xp Sp3 装机版|纯净版分享

[电脑城热销]深度技术 Ghost Xp Sp3 装机版|纯净版分享[深度完美 至尊精品]深度技术 Ghost Xp Sp3 通用装机版软件大小:1.46 GB软件语言:简体中文 授权方式:共享软件 更新时间:2015-03-10 类型:.iso 详情内容:http://www.win7g.com/xp/458.html下载地址:本地下载:http://down.os36.com/deepin_ghost_xp_zjb.iso (直接点击或复制打开)迅雷快传:http://kuai.xunlei

Windows7 SP1旗舰版精简版最终版本

2016年6月9号,老毛子@lopatkin大神针对Win7 SP1旗舰版精简版进行了最终更新,此次主要是之前小问题的修复和调整.该版为Windows 7 SP1 简体中文旗舰版最新版,包含2016年微软累积更新,经过国内众多系统爱好者检验,精简后体积比较小,适合低配电脑,非常稳定流畅!Win7爱好者们不妨下载收藏! 俄罗斯系统精简狂人@lopatkin 大侠一直专注于Windows操作系统的精简封装,每次微软有新的系统版本发布,他都会第一时间制作跟进发布.老毛子精简改进的系统以纯净流畅为主,无

Java 反编译工具 —— JAD 的下载地址(Windows版/Linux版/Mac OS 版)

Java 反编译工具 —— JAD 的下载地址. 各种版本哦! Windows版,Linux版,Mac OS 版,等等 下载地址: http://varaneckas.com/jad/ Java 反编译工具 -- JAD 的下载地址(Windows版/Linux版/Mac OS 版),布布扣,bubuko.com

bzoj3551 Peaks加强版 题解

这个题--感觉离线和在线的代码难度差不多(pb_ds不要说话). 离线的话,就是把所有询问按照w排个序,然后一边Kruskal+平衡树启发式合并一边回答询问就好了. 在线也不难写.首先Kruskal重构树(这个Kruskal重构树是不按秩合并还要添虚点的那种--),那么每个点可以到达的点一定在某个子树里.子树的dfs序是连续的,所以可以对dfs序建主席树来求区间k大.又因为只有叶子节点的点权是有意义的,所以可以只对叶子的dfs序建主席树.查询的时候倍增跳到最高的w<=询问的w的点然后主席树就好了