BZOJ4009 HNOI2015 接水果

Posted Fenghr

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ4009 HNOI2015 接水果相关的知识,希望对你有一定的参考价值。

4009: [Hnoi2015]接水果

Time Limit: 60 Sec  Memory Limit: 512 MB

Description

风见幽香非常喜欢玩一个叫做 osu!的游戏,其中她最喜欢玩的模式就是接水果。由于她已经DT FC 了The big black, 她觉得这个游戏太简单了,于是发明了一个更加难的版本。首先有一个地图,是一棵由 n 个顶点、n-1 条边组成的树(例如图 1给出的树包含 8 个顶点、7 条边)。这颗树上有 P 个盘子,每个盘子实际上是一条路径(例如图 1 中顶点 6 到顶点 8 的路径),并且每个盘子还有一个权值。第 i 个盘子就是顶点aiai到顶点bibi的路径(由于是树,所以从aiai到bibi 的路径是唯一的), 权值为cici。接下来依次会有Q个水果掉下来,每个水果本质上也是一条路径,第i 个水果是从顶点 uiui 到顶点vivi 的路径。 
幽香每次需要选择一个盘子去接当前的水果:一个盘子能接住一个水果,当且仅当盘子的路径是水果的路径的子路径(例如 图1中从 3到7 的路径是从1到8的路径的子路径)。 
这里规定:从a 到b的路径与从b到 a的路径是同一条路径。当然为了提高难度,对于第 i 个水果,你需要选择能接住它的所有盘子中,权值第 kiki 小的那个盘子,每个盘子可重复使用(没有使用次数的上限:一个盘子接完一个水果后,后面还可继续接其他水果,只要它是水果路径的子路径)。幽香认为这个游戏很难,你能轻松解决给她看吗? 
技术分享

Input

第一行三个数 n和P 和Q,表示树的大小和盘子的个数和水果的个数。 
接下来n-1 行,每行两个数 a、b,表示树上的a和b 之间有一条边。树中顶点按1到 n标号。 
接下来 P 行,每行三个数 a、b、c,表示路径为 a 到 b、权值为 c 的盘子,其中0≤c≤109109,a不等于b。 
接下来Q行,每行三个数 u、v、k,表示路径为 u到 v的水果,其中 u不等于v,你需要选择第 k小的盘子,第k 小一定存在。

Output

对于每个果子,输出一行表示选择的盘子的权值。

Sample Input

10 10 10 
1 2 
2 3 
3 4 
4 5 
5 6 
6 7 
7 8 
8 9 
9 10 
3 2 217394434 
10 7 13022269 
6 7 283254485 
6 8 333042360 
4 6 442139372 
8 3 225045590 
10 4 922205209 
10 8 808296330 
9 2 486331361 
4 9 551176338 
1 8 5 
3 8 3 
3 8 4 
1 8 3 
4 8 1 
2 3 1 
2 3 1 
2 3 1 
2 4 1 
1 4 1

Sample Output

442139372 
333042360 
442139372 
283254485 
283254485 
217394434 
217394434 
217394434 
217394434 
217394434

Hint

技术分享

  我没有权限号...因为时限大就变成权限题真的好吗?

  好像我也讲不出什么不好的道理。

  这题挺有意思的,对于我这种码废+代码能力差+思维混乱+弱的人来说,这题挺杀时间的...一个上午就给它跪了。

  啊反正你就是能把一个盘子变成一个或者两个矩形?把一个水果变成一个点?

  然后就是统计覆盖点的权值第k小的矩形是哪个?

  hin有道理啊我为什么就是想不出来呢呢呢?

  然后如果你会扫描线的话 就是一道整体二分裸题了?

  如果不会的话,你肯定会差分是吧...

  把一个矩形按x轴拆成左加右减,树状数组搞搞。

  然后就是一道整体二分裸题了?

  为什么一个个 一百行都不要的 我却打了这么多呢?

  思维混乱+弱啊!

  注意数组要开两倍,因为盘子可能有两个。

#include   <iostream>
#include   <cstdio>
#include <cstdlib> #include <algorithm> #include <vector> #include <cstring> #include <queue> #include <complex> #include <stack> #define LL long long int #define dob double using namespace std; const int N = 40010; struct Node{int to,next;}E[N<<1]; struct Plate{ int xl,xr,yl,yr,val; bool operator <(const Plate &p)const{ return val<p.val; } }plate[N<<1]; struct Fruit{ int x,y,k,id; bool operator <(const Fruit &f)const{ return x<f.x; } }fruit[N],que1[N],que2[N]; struct Data{ int x,l,r,val; bool operator <(const Data &l)const{ return x<l.x; } }Line[N<<1]; int n,P,Q,Ans[N],cnt,head[N],tot; int fa[21][N],dep[N],size[N],son[N],top[N],dfn[N],tim,last[N]; struct Bit{ int A[N],vis[N]; inline int lb(int x){ return x&-x; } inline void upd(int x,int val){ for(;x<=n;x+=lb(x)){ if(vis[x]!=tim)A[x]=0,vis[x]=tim; A[x]+=val; } } inline void update(int l,int r,int val){ upd(l,val);upd(r+1,-val); } inline int query(int x,int ans=0){ for(;x;x-=lb(x)){ if(vis[x]!=tim)A[x]=0,vis[x]=tim; ans+=A[x]; } return ans; } }T; inline int gi(){ int x=0,res=1;char ch=getchar(); while(ch>‘9‘||ch<‘0‘){if(ch==‘-‘)res*=-1;ch=getchar();} while(ch<=‘9‘&&ch>=‘0‘)x=x*10+ch-48,ch=getchar(); return x*res; } inline void link(int u,int v){ E[++tot]=(Node){v,head[u]}; head[u]=tot; } inline void join(int x){ for(int i=1;i<=15;++i) fa[i][x]=fa[i-1][fa[i-1][x]]; } inline void dfs1(int x,int fat){ fa[0][x]=fat;dep[x]=dep[fat]+1;join(x); dfn[x]=++tim; for(int e=head[x];e;e=E[e].next){ int y=E[e].to;if(y==fa[0][x])continue; dfs1(y,x); } last[x]=tim; } inline int lca(int x,int y){ if(x==y)return x; if(dep[x]<dep[y])swap(x,y); for(int i=15;i>=0;--i) if(dep[fa[i][x]]>=dep[y]) x=fa[i][x]; if(x==y)return x; for(int i=15;i>=0;--i) if(fa[i][x]!=fa[i][y]) x=fa[i][x],y=fa[i][y]; return fa[0][x]; } inline int jump(int x,int goal){ for(int i=15;i>=0;--i) if(dep[fa[i][x]]>dep[goal]) x=fa[i][x]; return x; } /* 把答案(盘子)二分。 把左边的矩形加进去。 然后check,calc一下盘子个数,和k比较一下,划分一下。 递归处理。 */ inline void solve(int optl,int optr,int l,int r){ if(optl>optr || l>r)return;++tim; if(optl==optr){ for(int i=l;i<=r;++i) Ans[fruit[i].id]=plate[optl].val; return; } int mid=(optl+optr)>>1,tot1=0,tot2=0,k=l,tmp=0,cnt1=1,cnt2=l; for(int i=optl;i<=mid;++i){ Line[++tmp]=(Data){plate[i].xl,plate[i].yl,plate[i].yr,1}; Line[++tmp]=(Data){plate[i].xr+1,plate[i].yl,plate[i].yr,-1}; } sort(Line+1,Line+tmp+1); while(cnt1<=tmp && cnt2<=r){ if(Line[cnt1].x<=fruit[cnt2].x){ int xl=Line[cnt1].l,xr=Line[cnt1].r,val=Line[cnt1].val; T.update(xl,xr,val);cnt1++; } else{ int sum=T.query(fruit[cnt2].y); if(sum>=fruit[cnt2].k)que1[++tot1]=fruit[cnt2++]; else fruit[cnt2].k-=sum,que2[++tot2]=fruit[cnt2++]; } } while(cnt2<=r){ int sum=T.query(fruit[cnt2].y); if(sum>=fruit[cnt2].k)que1[++tot1]=fruit[cnt2++]; else fruit[cnt2].k-=sum,que2[++tot2]=fruit[cnt2++]; } for(int i=1;i<=tot1;++i)fruit[k++]=que1[i]; for(int i=1;i<=tot2;++i)fruit[k++]=que2[i]; solve(optl,mid,l,l+tot1-1); solve(mid+1,optr,l+tot1,r); } int main() { freopen("fruit_hnoi2015.in","r",stdin); freopen("fruit_hnoi2015.out","w",stdout); n=gi();P=gi();Q=gi(); for(int i=1;i<n;++i){ int u=gi(),v=gi(); link(u,v);link(v,u); } dfs1(1,1); for(int i=1;i<=P;++i){ int a=gi(),b=gi(),c=gi(),u=lca(a,b); if(dfn[a]>dfn[b])swap(a,b); if(u!=a)plate[++cnt]=(Plate){dfn[a],last[a],dfn[b],last[b],c}; else{ int v=jump(b,a); if(dfn[v]>1)plate[++cnt]=(Plate){1,dfn[v]-1,dfn[b],last[b],c}; if(last[v]<n)plate[++cnt]=(Plate){dfn[b],last[b],last[v]+1,n,c}; } } for(int i=1;i<=Q;++i){ int a=gi(),b=gi(),k=gi(); if(dfn[a]>dfn[b])swap(a,b); fruit[i]=(Fruit){dfn[a],dfn[b],k,i}; } sort(plate+1,plate+cnt+1); sort(fruit+1,fruit+Q+1); solve(1,cnt,1,Q); for(int i=1;i<=Q;++i)printf("%d\n",Ans[i]); return 0; }

  

 

以上是关于BZOJ4009 HNOI2015 接水果的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ4009 HNOI2015 接水果

BZOJ4009 [HNOI2015]接水果

bzoj4009 [HNOI2015]接水果

BZOJ4009 [HNOI2015] 接水果

BZOJ4009[HNOI2015]接水果 DFS序+整体二分+扫描线+树状数组

BZOJ4009 & 洛谷3242 & LOJ2113:[HNOI2015]接水果——题解

(c)2006-2024 SYSTEM All Rights Reserved IT常识