【Peaks加强版 BZOJ 3551】你被坑了吗?

这道在没加读入优化时间在20s左右的题终于在大米饼两天的死缠烂打、鬼混、乱整乱撞后艰难地AC了。但惋惜的是,大米饼一号代码其实更加简洁,但至今找不出BUG,我将它放在下面,也许有一天从远方来的另一个大米饼会拯救它。让我们一起念出这道题的关键字:

Kurskal,LCA倍增,Kurskal重构树,dfs序,主席树。

比较新鲜的是重构树,它有一些美妙性质。

红色的是由边化成的节点。用Kurskal建出这棵树,在这一棵树上进行DFS序处理,并且在DFS序上进行主席树(可持久化线段树)处理。有趣的是,这道题读入优化可以加速5s,是不是很美妙!

 1 #include<stdio.h>
 2 #include<algorithm>
 3 #include<cstring>
 4 #define ro(i,a,b) for(int i=a;i>=b;i--)
 5 #define go(i,a,b) for(int i=a;i<=b;i++)
 6 using namespace std;
 7 const int inf=2147483646;const int logp=18;const int N=1e5+233;
 8 const int M=5e5+233;const int P=N<<1;const int E=P<<1;const int S=P*logp ;
 9 int n,m,q,p,num,cnt,K,d[N],h[N],dad[P],val[P],rt[P],lc[S],rc[S],sum[S];
10 int si[P],dep[P],dfn[P],pos[P],head[P],nex[E],ver[E],fa[logp+1][P],pr[logp+1],lg[P];
11 struct edge{int x,y,z;};edge a[M];
12 bool cmp(edge a, edge b){return a.z<b.z;}
13 int find(int x){return dad[x]!=x?dad[x]=find(dad[x]):x;}
14 void ADD(int u, int v){nex[++K]=head[u];head[u]=K;ver[K]=v;}
15 void dfs(int u)
16 {
17     si[u]=1;dfn[u]=++num;pos[num]=u;
18     for(int i=head[u];i;i=nex[i])
19     {int v=ver[i];fa[0][v]=u;dep[v]=dep[u]+1;dfs(v);si[u]+=si[v];}
20 }
21 void Kruskal()
22 {
23     p=n;sort(a+1,a+1+m,cmp);
24     go(i,1,m){int x=find(a[i].x),y=find(a[i].y);
25     if(x!=y){dad[++p]=p;val[p]=a[i].z;dad[x]=dad[y]=p;
26     ADD(p,x),ADD(p,y);if(p==(n<<1)-1)break;}}
27 }
28 void Rmq()
29 {
30     go(k,1,lg[p])go(i,1,p){if(dep[i]<pr[k])continue;
31     fa[k][i]=fa[k-1][fa[k-1][i]];}
32 }
33 int Add(int p,int l,int r,int x)
34 {
35     int k=++cnt;sum[k]=sum[p]+1;if(l==r)return k;int mid=l+r>>1;
36     if(x<=mid)lc[k]=Add(lc[p],l,mid,x),rc[k]=rc[p];
37     else rc[k]=Add(rc[p],mid+1,r,x),lc[k]=lc[p];return k;
38 }
39 void prepare()
40 {
41     Kruskal();num=0;go(i,1,p)if(!dfn[i])dfs(find(i));pr[0]=1;
42     go(i,1,logp){pr[i]=pr[i-1]<<1;if(pr[i]>p)break;lg[pr[i]]=1;}
43     go(i,1,p)lg[i]+=lg[i-1];Rmq();go(i,1,num)
44     {int x=pos[i];if(x>n)rt[i]=rt[i-1];else rt[i]=Add(rt[i-1],1,n,h[x]);}
45 }
46 int Jump(int x, int v){
47     int len=lg[dep[x]];ro(i,len,0)if(val[fa[i][x]]<=v)x=fa[i][x];return x;
48 }
49 int Query(int a, int b, int l, int r, int k)
50 {
51     if(l==r)return l;int amo=sum[rc[b]]-sum[rc[a]];
52     int mi=l+r>>1;if(amo<k)return Query(lc[a],lc[b],l,mi,k-amo);
53     return Query(rc[a],rc[b],mi+1,r,k);
54 }
55 int Ask(int x, int v, int k)
56 {
57     int anc=Jump(x,v),beg=rt[dfn[anc]-1],end=rt[dfn[anc]+si[anc]-1];
58     if(sum[end]-sum[beg]<k)return -1;
59     int hi=Query(beg,end,1,n,k);return d[hi];
60 }
61 int main()
62 {
63     scanf("%d%d%d",&n,&m,&q);val[0]=inf;
64     go(i,1,n)scanf("%d",&h[i]),d[i]=h[i],dad[i]=i;
65     sort(d+1,d+1+n);go(i,1,n)h[i]=lower_bound(d+1,d+1+n,h[i])-d;
66     go(i,1,m)scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].z);
67     prepare();int ans=-1;while(q--)
68     {
69         int x,v,k;scanf("%d%d%d",&x,&v,&k);
70         if(ans != -1)x^=ans,v^=ans,k^=ans;
71         ans=Ask(x,v,k);printf("%d\n",ans);
72     }
73 }

【大米饼代码】

下面是暂时RE的代码:

 1 #include<stdio.h>
 2 #include<algorithm>
 3 #define go(i,a,b) for(int i=a;i<=b;i++)
 4 #define ro(i,a,b) for(int i=a;i>=b;i--)
 5 #define rule 1000000000
 6 using namespace std;const int N=100003;struct TT{int siz,l,r;}t[N*20];
 7 struct G{int u,v,w;bool operator<(const G&X)const{return w<X.w;};}g[N*20];
 8 int n,m,q,fa[N],ch[N][2],SZ,sz,val[N],root,v,x,k,ans=0,T[N];
 9 int up[N][20],dis[N][20],start[N],end[N],dfs_clock,DFS[N],ROOT[N];
10 int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
11 int get_root(int x,int val){ro(j,19,0)if(up[x][j]&&dis[x][j]<=val)x=up[x][j];return x;}
12 void dfs(int u){if(!u)return;start[u]=dfs_clock;
13     if(ch[u][1]+ch[u][0]<1)DFS[++dfs_clock]=val[u];
14     go(i,0,1)dfs(ch[u][i]);end[u]=dfs_clock;
15 }
16 void insert(int& x,int Val,int l,int r){
17     t[++sz]=t[x];x=sz;++t[x].siz;if(l==r)return;
18     int mid=(l+r)/2;if(Val<=mid)insert(t[x].l,Val,l,mid);
19     else insert(t[x].r,Val,mid+1,r);
20 }
21 void Que(int i,int j,int k,int l,int r){
22     if( l==r ){ans=l;return;}
23     int tmp=t[t[j].l].siz-t[t[i].l].siz,mid=(r+l)/2;
24     if(k<=tmp)Que(t[i].l,t[j].l,k,l,mid);else Que(t[i].r,t[j].r,k-tmp,mid+1,r);
25 }
26 int main(){
27     freopen("in.in","r",stdin);
28     scanf("%d%d%d",&n,&m,&q);SZ=n;
29     go(i,1,n)scanf("%d",&val[i]),fa[i]=i;
30     go(i,1,m)scanf("%d%d%d",&g[i].u,&g[i].v,&g[i].w);
31     sort(g+1,g+m+1);int tot=n;go(i,1,m)
32     {
33         int Fa=find(g[i].u),Fb=find(g[i].v);
34         if(Fa==Fb)continue;if(!--tot)break;
35         int u=++SZ;fa[u]=fa[Fa]=fa[Fb]=u;
36         ch[u][0]=Fa,ch[u][1]=Fb;
37         up[Fa][0]=up[Fb][0]=u;
38         dis[Fa][0]=dis[Fb][0]=g[i].w;
39     }
40
41     dfs(SZ);go(i,1,n)ROOT[i]=ROOT[i-1],insert(ROOT[i],DFS[i],0,rule);
42     go(j,1,19)go(i,1,SZ)up[i][j]=up[up[i][j-1]][j-1],
43     dis[i][j]=max(dis[i][j-1],dis[up[i][j-1]][j-1]);
44
45     go(i,1,q)
46     {
47         scanf("%d%d%d",&v,&x,&k);x^=ans;v^=ans;k^=ans;
48         root=get_root(x,v);
49         int gap=end[root]-start[root];
50         if(gap<k){puts("-1");ans=0;continue;}
51         Que(ROOT[start[root]],ROOT[end[root]],gap-k+1,0,rule);
52         if(!ans){puts("-1");ans=0;continue;}printf("%d\n",ans);
53     }
54     return 0;
55 }//Paul_Guderian

【大米饼一号代码】

 

你没有达到顶尖!但记得给我买杯柠檬汁。

时间: 2024-12-22 15:09:30

【Peaks加强版 BZOJ 3551】你被坑了吗?的相关文章

【BZOJ 3545】【ONTAK 2010】Peaks &amp; 【BZOJ 3551】【ONTAK 2010】Peaks加强版 Kruskal重构树

sunshine的A题我竟然调了一周!!! 把循环dfs改成一个dfs就可以,,,我也不知道为什么这样就不会RE,但它却是A了,,, 这周我一直在调这个题,总结一下智障错误: 1.倍增的范围设成了n而不是n*2-1,,, 2.重构树的顶点是n*2-1,而我一开始设成了n,,, 3.define里的for3和for4的i--打成i++,,,,,,,,,,,, 4.dfs爆栈了,找CA爷问的编译命令里手动扩栈,真是愚蠢的问题,,,, 比赛时绝不会有太多时间,在这么犯逗就得滚粗了QAQ 3545: #

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

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

【BZOJ 3551】[ONTAK2010] Peaks加强版 Kruskal重构树+树上倍增+主席树

这题真刺激...... I.关于Kruskal重构树,我只能开门了,不过补充一下那玩意还是一棵满二叉树.(看一下内容之前请先进门坐一坐) II.原来只是用树上倍增求Lca,但其实树上倍增是一种方法,Lca只是他的一种应用,他可以搞各种树上问题,树上倍增一般都会用到f数组. |||.我们跑出来dfs序就能在他的上面进行主席树了. IV.别忘了离散. V.他可能不连通,我一开始想到了,但是我觉得出题人可能会是好(S)人(B),但是...... #include <cstdio> #include

bzoj 3551 [ONTAK2010]Peaks加强版(kruskal,主席树,dfs序)

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 [思路] Kruskal+主席树+dfs序 一个叫kruskal重构树的方法QWQ.在kruskal合

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

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

[BZOJ 3551] Peaks 半可持久化并查集 可持久化线段树合并

实现 1 #include <cstdio> 2 #include <cstring> 3 #include <cstdlib> 4 #include <cctype> 5 #include <algorithm> 6 #include <map> 7 using namespace std; 8 #define F(i, a, b) for (register int i = (a); i <= (b); i++) 9 inl

BZOJ 3545/BZOJ 3551 Peaks

kruskal重构树. #include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #define maxv 200050 #define maxe 2000050 #define inf 2147483647 using namespace std; struct edges { int u,v,w; }es[maxe]; struct edge { int v,nxt

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的路径所能到达