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_u\leq ls_x \leq rs_u,ls_v\leq 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)}\bigcup {(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]='\n';
 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 }

 

posted @ 2018-08-30 19:23  bztMinamoto  阅读(237)  评论(0编辑  收藏  举报
Live2D