bzoj3551 Peaks加强版 题解

这个题……感觉离线和在线的代码难度差不多(pb_ds不要说话)。

离线的话,就是把所有询问按照w排个序,然后一边Kruskal+平衡树启发式合并一边回答询问就好了。

在线也不难写。首先Kruskal重构树(这个Kruskal重构树是不按秩合并还要添虚点的那种……),那么每个点可以到达的点一定在某个子树里。子树的dfs序是连续的,所以可以对dfs序建主席树来求区间k大。又因为只有叶子节点的点权是有意义的,所以可以只对叶子的dfs序建主席树。查询的时候倍增跳到最高的w<=询问的w的点然后主席树就好了。

其实树剖跳父亲也可以,先跳整条链,整条链跳不动的时候就在最后一条链上二分,也是O(logn)的。不过可能是太弱,二分写挂了,结果WA到死……无奈用倍增重写了一遍。

限时20s,结果我跑了19.8s,这速度真是感人肺腑……

还有,copy的那个a一开始忘了+1了,调了一节课,虚死……

  1 /**************************************************************
  2     Problem: 3551
  3     User: hzoier
  4     Language: C++
  5     Result: Accepted
  6     Time:19800 ms
  7     Memory:114432 kb
  8 ****************************************************************/
  9 #include<cstdio>
 10 #include<cstring>
 11 #include<algorithm>
 12 using namespace std;
 13 const int maxn=200010,maxe=500010;
 14 struct edge{
 15     int from,to,w;
 16     bool operator<(const edge &e)const{return w<e.w;}
 17 }e[maxe+maxn];
 18 void Kruskal();
 19 int findroot(int);
 20 void mergeset(int,int);
 21 void dfs(int);
 22 void build(int,int,int&,int);
 23 void query(int,int,int,int);
 24 int sm[maxn<<5],lc[maxn<<5],rc[maxn<<5],root[maxn],tree_cnt=0;
 25 int n,M=0,m,q,h[maxn],a[maxn],cnt,prt[maxn],w[maxn],f[maxn][20],ch[maxn][2],L[maxn],R[maxn],pr=0,x,d,k,ans;
 26 int main(){
 27     scanf("%d%d%d",&n,&m,&q);
 28     while((1<<M)<(n<<1))M++;
 29     for(int i=1;i<=n;i++)scanf("%d",&h[i]);
 30     copy(h+1,h+n+1,a+1);
 31     sort(a+1,a+n+1);
 32     for(int i=1;i<=n;i++)h[i]=lower_bound(a+1,a+n+1,h[i])-a;
 33     for(int i=1;i<=m;i++)scanf("%d%d%d",&e[i].from,&e[i].to,&e[i].w);
 34     for(int i=2;i<=n;i++){
 35         e[++m].from=1;
 36         e[m].to=i;
 37         e[m].w=~(1<<31);
 38     }
 39     cnt=n;
 40     Kruskal();
 41     dfs(cnt);
 42     for(int j=1;j<=M;j++)for(int i=1;i<=cnt;i++)f[i][j]=f[f[i][j-1]][j-1];
 43     while(q--){
 44         scanf("%d%d%d",&x,&d,&k);
 45         if(ans!=-1){x^=ans;d^=ans;k^=ans;}
 46         for(int j=M;j!=-1;j--)if(f[x][j]&&w[f[x][j]]<=d)x=f[x][j];
 47         query(1,n,root[R[x]],root[L[x]-1]);
 48         printf("%d\n",ans);
 49     }
 50     return 0;
 51 }
 52 void Kruskal(){
 53     for(int i=1;i<=n;i++)prt[i]=i;
 54     stable_sort(e+1,e+m+1);
 55     for(int i=1;i<=m;i++)if(findroot(e[i].from)!=findroot(e[i].to)){
 56         cnt++;
 57         prt[cnt]=cnt;
 58         w[cnt]=e[i].w;
 59         ch[cnt][0]=findroot(e[i].from);
 60         ch[cnt][1]=findroot(e[i].to);
 61         mergeset(e[i].from,cnt);
 62         mergeset(e[i].to,cnt);
 63     }
 64 }
 65 int findroot(int x){return prt[x]==x?x:(prt[x]=findroot(prt[x]));}
 66 void mergeset(int x,int y){prt[findroot(x)]=findroot(y);}
 67 void dfs(int x){
 68     if(ch[x][0]){
 69         f[ch[x][0]][0]=f[ch[x][1]][0]=x;
 70         dfs(ch[x][0]);
 71         dfs(ch[x][1]);
 72         L[x]=L[ch[x][0]];
 73         R[x]=R[ch[x][1]];
 74     }
 75     else{
 76         k=h[x];
 77         build(1,n,root[pr+1],root[pr]);
 78         L[x]=R[x]=++pr;
 79     }
 80 }
 81 void build(int l,int r,int &rt,int pr){
 82     sm[rt=++tree_cnt]=sm[pr]+1;
 83     if(l==r)return;
 84     lc[rt]=lc[pr];rc[rt]=rc[pr];
 85     int mid=(l+r)>>1;
 86     if(k<=mid)build(l,mid,lc[rt],lc[pr]);
 87     else build(mid+1,r,rc[rt],rc[pr]);
 88 }
 89 void query(int l,int r,int rt,int pr){
 90     if(sm[rt]-sm[pr]<k){
 91         ans=-1;
 92         return;
 93     }
 94     if(l==r){
 95         ans=a[l];
 96         return;
 97     }
 98     int mid=(l+r)>>1;
 99     if(k<=sm[rc[rt]]-sm[rc[pr]])query(mid+1,r,rc[rt],rc[pr]);
100     else{
101         k-=sm[rc[rt]]-sm[rc[pr]];
102         query(l,mid,lc[rt],lc[pr]);
103     }
104 }

尽头和开端,总有一个在等你。

时间: 2024-10-14 13:41:08

bzoj3551 Peaks加强版 题解的相关文章

bzoj3545 [ONTAK2010]Peaks、bzoj3551 [ONTAK2010]Peaks加强版

题目描述: bzoj3545,luogu bzoj3551 题解: 重构树+线段树合并. 可以算是板子了吧. 代码(强制在线): #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N = 100050; const int M = 5*N; template<typename T> inline void read(T&x) {

bzoj3545/bzoj3551 [ONTAK2010]Peaks/Peaks加强版

传送门:bzoj  bzoj wdnmd为什么加强版不是权限题原题却是啊 3545: [ONTAK2010]Peaks Time Limit: 10 Sec  Memory Limit: 128 MB[Submit][Status][Discuss] Description 在Bytemountains有N座山峰,每座山峰有他的高度h_i.有些山峰之间有双向道路相连,共M条路径,每条路径有一个困难值,这个值越大表示越难走,现在有Q组询问,每组询问询问从点v开始只经过困难值小于等于x的路径所能到达

bzoj3551 [ONTAK2010]Peaks加强版

Description //[题目描述]同3545 在Bytemountains有N座山峰,每座山峰有他的高度h_i.有些山峰之间有双向道路相连,共M条路径,每条路径有一个困难值,这个值越大表示越难走,现在有Q组询问,每组询问询问从点v开始只经过困难值小于等于x的路径所能到达的山峰中第k高的山峰,如果无解输出-1. Input 第一行三个数N,M,Q. 第二行N个数,第i个数为h_i 接下来M行,每行3个数a b c,表示从a到b有一条困难值为c的双向路径. 接下来Q行,每行三个数v x k,表

bzoj 3545&amp;&amp;3551: [ONTAK2010]Peaks &amp;&amp;加强版 平衡树&amp;&amp;并查集合并树&amp;&amp;主席树

3545: [ONTAK2010]Peaks Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 635  Solved: 177[Submit][Status] Description 在Bytemountains有N座山峰,每座山峰有他的高度h_i.有些山峰之间有双向道路相连,共M条路径,每条路径有一个困难值,这个值越大表示越难走,现在有Q组询问,每组询问询问从点v开始只经过困难值小于等于x的路径所能到达的山峰中第k高的山峰,如果无解输出-1. I

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

题目给n点m边的无向图,有点权和边权 每次询问求点v在经过路径上的边都不超过w的情况下,能到达的第k大的点的权值 首先离线版比较容易想到,属于我现在能码出来的最难的码农题之一吧T T 这道题思路是这样的 1.对于边权的限制条件,可以先想到做一棵最小生成树 2.对于第k大这种询问,可以建权值线段树,但是山的高度太大到1e9,所以我们还要先离散化到1e6的水平才能用线段树 3.显然不能对每个询问w都建线段树,因此要用到主席树.具体做法是将询问和边权都排序(详情看代码),给每个点建一棵线段树,然后边建

bzoj 3551: [ONTAK2010]Peaks加强版

Description [题目描述]同3545 Input 第一行三个数N,M,Q. 第二行N个数,第i个数为h_i 接下来M行,每行3个数a b c,表示从a到b有一条困难值为c的双向路径. 接下来Q行,每行三个数v x k,表示一组询问.v=v xor lastans,x=x xor lastans,k=k xor lastans.如果lastans=-1则不变. Output 同3545 Sample Input Sample Output HINT [数据范围]同3545 Source

bzoj2594水管局长数据加强版题解(未完待续)

题目大意 给一张带权无向图,无重边和自环,有如下操作: 删除某条边,保证这条边在删除前一定存在,并且不破坏原图连通性: 询问两点之间所有路径中最小权值的最大值是多少: 题解 问题的答案显然在原图的最小生成树上,于是本题就变成了动态维护删边最小生成树. 然而LinkCutTree维护最小生成树时并不支持删边操作,所以要离线处理,先删掉该删掉的边,再求最小生成树,把所有操作倒过来用LCT维护. 如何用LCT维护动态添边最小生成树 设原图中有n个点,m条边: 把每条边视为一个点,编号为n+1,n+2,

BZOJ 3551 ONTAK2010 Peaks加强版 Kruskal重构树+可持久化线段树

题目大意:同3545 强制在线 3545题解传送门:http://blog.csdn.net/popoqqq/article/details/40660953 强制在线没法排序 启发式合并也就用不了了 Kruskal重构树是个挺好玩的东西 可以拿来处理一些最小生成树的边权最值问题 这里我们Kruskal连边时并不直接连边 而是新建一个节点ext 将两个点所在子树都连到ext的儿子上 比如说样例的树就建成了这样 图中红色的是原图的边权,黑色的是原图上的点 这样生成的树有一些十分优美的性质: 1.二

ONTAK2010 Peaks加强版

给一个图,每个点有点权,$q$ 次询问从 $x$ 开始只走点权小于等于 $y$ 的路径能到的点中第 $k$ 大的点权,无解输出 -1 强制在线 请注意因为这个 sb 博主为了描述方便,这里的题目描述用的字母跟原题有出入,题解跟跟这里的题目描述一样,不一定跟 bzoj 上一样( $n \leq 10^5$ $m,q \leq 5 \times 10^5$ 点权$\leq 10^9$ sol: Kruskal 重构树,每次能走的是一个子树 于是我们可以先倍增找到能走的最高的点(倍增找到重构树上点权小