zoukankan      html  css  js  c++  java
  • [BZOJ4009][HNOI2015]接水果(整体二分)

    [HNOI2015]接水果

    时间限制:60s      空间限制:512MB

    题目描述

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

    输入格式

    第一行三个数 n和P 和Q,表示树的大小和盘子的个数和水果的个数。 

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

    输出格式

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


    样例输入

    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 

    样例输出

    442139372 
    333042360 
    442139372 
    283254485 
    283254485 
    217394434 
    217394434 
    217394434 
    217394434 
    217394434 
     

    提示

    N,P,Q<=40000。 


    题目来源

    没有写明来源

    类似HNOI2017的影魔,思想是把对象映射到平面上。

    代码用时:1.5h。非常裸,整体二分加扫描线,树状数组代替线段树既省时有省力。

     1 #include<cstdio>
     2 #include<algorithm>
     3 #define rep(i,l,r) for (int i=l; i<=r; i++)
     4 #define For(i,x) for (int i=h[x],k; i; i=nxt[i])
     5 using namespace std;
     6 
     7 const int N=80100;
     8 int n,m,q,a,b,c,k,u,cnt,fa[N][18],dfn[N],tim,lst[N],v[N],dep[N],ans[N],sum[N],nxt[N],h[N],to[N],tot;
     9 struct P{ int x1,x2,y1,y2,v; }p[N];
    10 struct D{ int x,y1,y2,v,id; }d[N];
    11 struct Q{int x,y,k,id; }pnt[N],t1[N],t2[N];
    12 bool operator <(P a,P b){ return a.v<b.v; }
    13 bool operator <(D a,D b){ return a.x==b.x ? a.id<b.id : a.x<b.x; }
    14 void add(int u,int v){ nxt[++tot]=h[u]; h[u]=tot; to[tot]=v; }
    15 int que(int x){ int res=0; for (; x; x-=(x&(-x))) res+=v[x]; return res; }
    16 
    17 void mdf(int l,int r,int k){
    18     for (int i=l; i<=n; i+=(i&(-i))) v[i]+=k;
    19     for (int i=r+1; i<=n; i+=(i&(-i))) v[i]-=k;
    20 }
    21 
    22 void dfs(int x){
    23     dfn[x]=++tim;
    24     rep(i,1,17) fa[x][i]=fa[fa[x][i-1]][i-1];
    25     For(i,x) if ((k=to[i])!=fa[x][0]) fa[k][0]=x,dep[k]=dep[x]+1,dfs(k);
    26     lst[x]=tim;
    27 }
    28 
    29 int go(int a,int h){ for (int i=16; ~i; i--) if (h&(1<<i)) a=fa[a][i]; return a; }
    30 
    31 int lca(int a,int b){
    32     if (dep[a]<dep[b]) swap(a,b);
    33     a=go(a,dep[a]-dep[b]);
    34     if (a==b) return a;
    35     for (int i=16; ~i; i--) if (fa[a][i]!=fa[b][i]) a=fa[a][i],b=fa[b][i];
    36     return fa[a][0];
    37 }
    38 
    39 void solve(int l,int r,int st,int ed){
    40     if (st>ed) return;
    41     if (l==r){ rep(i,st,ed) ans[pnt[i].id]=p[l].v; return; }
    42     int mid=(l+r)>>1,sz=0;
    43     rep(i,l,mid){
    44         d[++sz]=(D){p[i].x1,p[i].y1,p[i].y2,1,0};
    45         d[++sz]=(D){p[i].x2,p[i].y1,p[i].y2,-1,n+1};
    46     }
    47     rep(i,st,ed) d[++sz]=(D){pnt[i].x,pnt[i].y,0,0,i};
    48     sort(d+1,d+sz+1);
    49     rep(i,1,sz)
    50         if (st<=d[i].id && d[i].id<=ed) sum[d[i].id]=que(d[i].y1);
    51             else mdf(d[i].y1,d[i].y2,d[i].v);
    52     int a=0,b=0;
    53     rep(i,st,ed)
    54         if (sum[i]>=pnt[i].k) t1[++a]=pnt[i];
    55         else t2[++b]=(Q){pnt[i].x,pnt[i].y,pnt[i].k-sum[i],pnt[i].id};
    56     rep(i,st,st+a-1) pnt[i]=t1[i-st+1];
    57     rep(i,st+a,ed) pnt[i]=t2[i-st-a+1];
    58     solve(l,mid,st,st+a-1); solve(mid+1,r,st+a,ed);
    59 }
    60 
    61 int main(){
    62     freopen("bzoj4009.in","r",stdin);
    63     freopen("bzoj4009.out","w",stdout);
    64     scanf("%d%d%d",&n,&m,&q);
    65     rep(i,1,n-1) scanf("%d%d",&a,&b),add(a,b),add(b,a);
    66     dfs(1);
    67     rep(i,1,m){
    68         scanf("%d%d%d",&a,&b,&c); u=lca(a,b);
    69         if (dfn[a]>dfn[b]) swap(a,b);
    70         if (u!=a) p[++cnt]=(P){dfn[a],lst[a],dfn[b],lst[b],c};
    71         else{
    72             int w=go(b,dep[b]-dep[a]-1);
    73             p[++cnt]=(P){1,dfn[w]-1,dfn[b],lst[b],c};
    74             if (lst[w]<n) p[++cnt]=(P){dfn[b],lst[b],lst[w]+1,n,c};
    75         }
    76     }
    77     sort(p+1,p+cnt+1);
    78     rep(i,1,q){
    79         scanf("%d%d%d",&a,&b,&k);
    80         if (dfn[a]>dfn[b]) swap(a,b);
    81         pnt[i]=(Q){dfn[a],dfn[b],k,i};
    82     }
    83     solve(1,cnt,1,q);
    84     rep(i,1,q) printf("%d
    ",ans[i]);
    85     return 0;
    86 }
  • 相关阅读:
    BadUSB 利用
    java 将函数作为参数传递
    odoo12 修行提升篇之 常用的高阶函数 (二)
    odoo12 修行提升篇之 异步定时任务 (一)
    odoo12 修行基础篇之 利用kanban做分析 点击跳转分析模型列表 (九)
    odoo12 修行基础篇之 kanban (八)
    odoo12 修行基础篇之 记录批处理 (七)
    odoo12 修行基础篇之 列表的筛选和分组 (六)
    odoo12 修行基础篇之 添加记录编码 (五)
    odoo12 修行基础篇之 添加工作流和操作记录 (四)
  • 原文地址:https://www.cnblogs.com/HocRiser/p/8325063.html
Copyright © 2011-2022 走看看