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

    题目描述

    风见幽香非常喜欢玩一个叫做 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 小的那个盘子,每个盘子可重复使用(没有使用次数的上限:一个盘子接完一个水果后,后面还可继续接其他水果,只要它是水果路径的子路径)。幽香认为这个游戏很难,你能轻松解决给她看吗? < width="395" height="212" alt="" />

    输入输出格式

    输入格式:

    第一行三个数 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 小一定存在。

    输出格式:

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

    输入输出样例

    输入样例#1: 复制
    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
    输出样例#1: 复制
    442139372 
    333042360 
    442139372 
    283254485 
    283254485 
    217394434 
    217394434 
    217394434 
    217394434 
    217394434

    说明

    N,P,Q<=40000。

    题解

      收获良多……知道了整体二分是个啥……知道了不用CDQ直接求矩形覆盖……balabala(我很好奇自己是怎么看懂题解的)

      先考虑一下怎么判断一条路径是否被另一条路劲覆盖

      我们记录一下每一个点的dfs序,其中$ls_u=dfn_u,rs_u=dfn_u+size_u-1$,这个应该是基本操作

      然后我们考虑一下

      我们把路径表示为二维平面上的一个点,$(ls_u,ls_v)(ls_u<ls_v)$,设询问为$x->y$且$ls_x<ls_y$

      如果$lca(u,v)!=u$,那么必定满足$x$在$u$的子树里,$y$在$v$的子树内,也就满足$ls_uleq ls_x leq rs_u,ls_vleq ls_y leq rs_v$,那么就是点$(ls_x,ls_y)$在矩形${(ls_u,ls_v),(rs_u,rs_v)}$里面

      如果$lca(u,v)==u$,那么设$z$为$u->v$路径上的第一个点,那么必定有一个点在$v$子树内,另一个点在$v$子树外,就是点$(ls_x,ls_y)$在矩形${(1,ls_v),(ls_z-1,rs_v)}igcup {(ls_v,rs_z+1),(rs_v,n)}$里面

      那么我们可以整体二分,二分一个答案,然后统计每一个点被矩形覆盖了多少次,然后不断这样做下去就行了

      至于怎么快速求一个点被矩形覆盖多少次,可以先排序去掉$x$的影响,然后用树状数组存储前缀和并查询

      1 //minamoto
      2 #include<iostream>
      3 #include<cstdio>
      4 #include<algorithm>
      5 using namespace std;
      6 #define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
      7 char buf[1<<21],*p1=buf,*p2=buf;
      8 inline int read(){
      9     #define num ch-'0'
     10     char ch;bool flag=0;int res;
     11     while(!isdigit(ch=getc()))
     12     (ch=='-')&&(flag=true);
     13     for(res=num;isdigit(ch=getc());res=res*10+num);
     14     (flag)&&(res=-res);
     15     #undef num
     16     return res;
     17 }
     18 char sr[1<<21],z[20];int C=-1,Z;
     19 inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;}
     20 inline void print(int x){
     21     if(C>1<<20)Ot();if(x<0)sr[++C]=45,x=-x;
     22     while(z[++Z]=x%10+48,x/=10);
     23     while(sr[++C]=z[Z],--Z);sr[++C]='
    ';
     24 }
     25 const int N=40005;
     26 int ver[N<<1],Next[N<<1],head[N],tot=0;
     27 int val[N],fa[N],dep[N],son[N],sz[N],ls[N],rs[N],top[N];
     28 int n,p,q,cnt,num;
     29 inline void add(int u,int v){
     30     ver[++tot]=v,Next[tot]=head[u],head[u]=tot;
     31     ver[++tot]=u,Next[tot]=head[v],head[v]=tot;
     32 }
     33 void dfs1(int u){
     34     sz[u]=1,dep[u]=dep[fa[u]]+1;
     35     for(int i=head[u];i;i=Next[i]){
     36         int v=ver[i];
     37         if(v!=fa[u]){
     38             fa[v]=u,dfs1(v),sz[u]+=sz[v];
     39             if(sz[v]>sz[son[u]]) son[u]=v;
     40         }
     41     }
     42 }
     43 void dfs2(int u,int t){
     44     top[u]=t,ls[u]=++num;
     45     if(son[u]){
     46         dfs2(son[u],t);
     47         for(int i=head[u];i;i=Next[i]){
     48             int v=ver[i];
     49             if(v!=fa[u]&&v!=son[u]) dfs2(v,v);
     50         }
     51     }
     52     rs[u]=num;
     53 }
     54 inline int LCA(int u,int v){
     55     while(top[u]!=top[v]){
     56         if(dep[top[u]]<dep[top[v]]) swap(u,v);
     57         u=fa[top[u]];
     58     }
     59     return dep[u]<dep[v]?u:v;
     60 }
     61 inline int find(int u,int v){
     62     while(top[u]!=top[v]){
     63         if(fa[top[v]]==u) return top[v];
     64         v=fa[top[v]];
     65     }
     66     return son[u];
     67 }
     68 int ans[N],sum[N],c[N];
     69 inline void update(int l,int r,int val){
     70     for(;l<=n;l+=l&-l) c[l]+=val;
     71     for(++r;r<=n;r+=r&-r) c[r]-=val;
     72 }
     73 inline int query(int x){
     74     int res=0;
     75     for(;x;x-=x&-x) res+=c[x];
     76     return res;
     77 }
     78 struct plate{int x1,x2,y1,y2,val;}pl[N<<1];
     79 struct fruit{int x,y,k,id;}fr[N],tmp1[N],tmp2[N];
     80 struct node{int x,y1,y2,val,id;}eve[N*5];
     81 inline bool cmp(const plate &a,const plate &b){return a.val<b.val;}
     82 inline bool cmp2(const node &a,const node &b){return a.x==b.x?a.id<b.id:a.x<b.x;}
     83 void solve(int l,int r,int ql,int qr){
     84     if(ql>qr) return;
     85     if(l==r){
     86         for(int i=ql;i<=qr;++i) ans[fr[i].id]=pl[l].val;
     87         return;
     88     }
     89     int a=0,b=0,mid=l+r>>1,tot=0;
     90     for(int i=l;i<=mid;++i)
     91     eve[++tot]=(node){pl[i].x1,pl[i].y1,pl[i].y2,1,0},
     92     eve[++tot]=(node){pl[i].x2,pl[i].y1,pl[i].y2,-1,q+1};
     93     for(int i=ql;i<=qr;++i)
     94     eve[++tot]=(node){fr[i].x,fr[i].y,0,0,i};
     95     sort(eve+1,eve+1+tot,cmp2);
     96     for(int i=1;i<=tot;++i)
     97     if(ql<=eve[i].id&&qr>=eve[i].id) sum[eve[i].id]=query(eve[i].y1);
     98     else update(eve[i].y1,eve[i].y2,eve[i].val);
     99     for(int i=ql;i<=qr;++i)
    100     if(sum[i]>=fr[i].k) tmp1[++a]=fr[i];
    101     else tmp2[++b]=fr[i],tmp2[b].k-=sum[i];
    102     for(int i=1;i<=a;++i) fr[i+ql-1]=tmp1[i];
    103     for(int i=1;i<=b;++i) fr[i+ql+a-1]=tmp2[i];
    104     solve(l,mid,ql,ql+a-1),solve(mid+1,r,ql+a,qr);
    105 }
    106 int main(){
    107     //freopen("testdata.in","r",stdin);
    108     n=read(),p=read(),q=read();
    109     for(int i=1;i<n;++i){
    110         int u=read(),v=read();add(u,v);
    111     }
    112     dfs1(1),dfs2(1,1);
    113     for(int i=1;i<=p;++i){
    114         int u=read(),v=read(),e=read(),lca=LCA(u,v);
    115         if(ls[u]>ls[v]) u^=v^=u^=v;
    116         if(u!=lca)
    117         pl[++cnt]=(plate){ls[u],rs[u],ls[v],rs[v],e};
    118         else{
    119             int x=find(u,v);
    120             if(ls[x]>1) pl[++cnt]=(plate){1,ls[x]-1,ls[v],rs[v],e};
    121             if(rs[x]<n) pl[++cnt]=(plate){ls[v],rs[v],rs[x]+1,n,e};
    122         }
    123     }
    124     for(int i=1;i<=q;++i){
    125         int u=read(),v=read(),e=read();
    126         if(ls[u]>ls[v]) u^=v^=u^=v;
    127         fr[i]=(fruit){ls[u],ls[v],e,i};
    128     }
    129     sort(pl+1,pl+1+cnt,cmp),solve(1,cnt,1,q);
    130     for(int i=1;i<=q;++i) print(ans[i]);
    131     Ot();
    132     return 0;
    133 }
  • 相关阅读:
    HTML 嵌入 SWF ,访问域的问题
    Flex 4 中,StageScaleMode 设置
    一句话清除MC下所有的子
    DataGrid 表头标题,表格文字的字体设置
    Flash中,将某个元件置于最顶层
    Android开发中使用SQLite 数据库
    Android多分辨率支持说明
    Android adb shell 命令大全
    Android Camera 使用小结
    Android多分辨率支持以及各种类型图标尺寸大小
  • 原文地址:https://www.cnblogs.com/bztMinamoto/p/9562138.html
Copyright © 2011-2022 走看看