【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 小的那个盘子,每个盘子可重复使用(没有使用次数的上限:一个盘子接完一个水果后,后面还可继续接其他水果,只要它是水果路径的子路径)。幽香认为这个游戏很难,你能轻松解决给她看吗? 

输入输出格式

输入格式:

 

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

 

输出格式:

 

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

题意:统计对于给出一些有权值的点对(盘子),再给出一些询问点对(水果),每个水果能被一个盘子接住当且仅当盘子的两点间的路径是水果两点之间路径的子路径。

题解:

①转化一下:一个盘子A可以接住一个水果B,意思是要么是A.x和A.y无祖先关系时,B.x和B.y都在A.x和A.y(可以交换位置)的子树里,要么是A.x和A.y有祖先关系:假设A.x是A.y的祖先,B.x一定在A.y的子树里且B.y一定不在A.x到A.y路径上的第二个点(第一个点为A.x)的子树里(同样可以交换)。

(还是给个图吧)

②用dfs序维护一下子树信息,一个子树成为一个连续的一段,找x到y的第二个点可以LCA或者树剖每次往上跳即可。

③现在相当于每个盘子可以转化成一个矩形:整体二分,用扫描线的思想维护一下每次的答案。把所有矩形和询问点按横坐标的大小排序,想像有一条从左向右的直线,扫到的横坐标为一个矩形的起点是把这个区间的[l,r]加入树状数组里,终点时再去掉。询问变为纵坐标的询问就可以在树状数组内完成。

 

  1 #include<cstdio>
  2 #include<iostream>
  3 #include<algorithm>
  4 using namespace std;
  5 const int N = 40010;
  6 int n,m;
  7 int o,hd[N],v[2*N],nt[2*N],son[N],top[N],size[N],st[N],ed[N],dep[N],idx,fa[N],ans[N],k;
  8 char gc(){
  9     static char *p1,*p2,s[1000000];
 10     if(p1==p2) p2=(p1=s)+fread(s,1,1000000,stdin);
 11     return(p1==p2)?EOF:*p1++; 
 12 }
 13 int rd(){
 14     int x = 0,f = 1; char c = gc();
 15     while(c<'0'||c>'9') {if(c=='-') f=-1;c = gc();}
 16     while(c>='0'&&c<='9') x=x*10+c-'0',c=gc();
 17     return x*f; 
 18 }///
 19 void adde(int x,int y){v[o]=y;nt[o]=hd[x];hd[x]=o++;} ///
 20 void Adde(int u,int v){adde(u,v);adde(v,u);}///
 21 void dfsA(int u){
 22     size[u] = 1; st[u] = ++idx; 
 23     for(int i=hd[u];i!=-1;i=nt[i]){
 24         if(v[i]==fa[u]) continue;
 25         fa[v[i]] = u;
 26         dfsA(v[i]); 
 27         size[u] += size[v[i]];
 28         if(size[v[i]]>size[son[u]]) son[u] = v[i];
 29     }
 30     ed[u] = idx;
 31 }///
 32 void dfsB(int u,int Top){
 33     top[u] = Top; dep[u]=dep[fa[u]]+1;
 34     if(son[u]) dfsB(son[u],Top);
 35     for(int i=hd[u];i!=-1;i=nt[i]){
 36         if(v[i]==fa[u]||v[i]==son[u]) continue;
 37         dfsB(v[i],v[i]);
 38     }
 39 }///
 40 int find(int x,int y){
 41     int tmp=x;
 42     while(top[x]!=top[y]) tmp=top[x],x=fa[top[x]];
 43     return x==y?tmp:son[y];
 44 }///
 45 struct edge{int l,r,x1,y1,x2,y2,w;
 46 bool operator <(const edge &a)const{return w<a.w;}
 47 }e[N];///
 48 struct A{int id,x,y,k;}a[N],tmp[N];///
 49 struct B{int p,x,y,d;
 50 bool operator<(const B&a)const{return p<a.p;}
 51 }b[4*N];///
 52 struct C{int id,x,y;
 53 bool operator<(const C&a)const{return x<a.x;}
 54 }c[2*N];///
 55 int tot,cnt,bit[N],now[N];
 56 void add(int x,int y){for(;x<=n;x+=x&-x)bit[x]+=y;}
 57 int ask(int x){int ret=0;for(;x;x-=x&-x)ret+=bit[x];return ret;}//
 58 void erfn(int l,int r,int L,int R){
 59     if(L>R) return ;
 60     if(l==r){
 61         for(int i=L;i<=R;i++) ans[a[i].id]=e[l].w;
 62         return; 
 63     }
 64     int mid=l+r>>1,tb=0,tc=0,tl=L,tr=0;
 65     for(int i=l;i<=mid;i++){
 66         if(e[i].x1<=e[i].y1){
 67             b[++tb] = (B){e[i].l,e[i].x1,e[i].y1,1};
 68             b[++tb] = (B){e[i].r+1,e[i].x1,e[i].y1,-1};
 69         }
 70         if(e[i].x2<=e[i].y2){
 71             b[++tb] = (B){e[i].l,e[i].x2,e[i].y2,1};
 72             b[++tb] = (B){e[i].r+1,e[i].x2,e[i].y2,-1};
 73         }
 74     }
 75     sort(b+1,b+tb+1);
 76     for(int i=L;i<=R;i++){
 77         c[++tc] = (C){i,a[i].x,a[i].y};
 78         c[++tc] = (C){i,a[i].y,a[i].x};
 79         now[i] = 0;
 80     } 
 81     sort(c+1,c+tc+1);
 82     int j=1;
 83     for(int i=1;i <= tc;i++){
 84         while(j<=tb&&b[j].p<=c[i].x) add(b[j].x,b[j].d),add(b[j].y+1,-b[j].d),j++;
 85         now[c[i].id]+=ask(c[i].y);
 86     }
 87     for(int i=j;i<=tb;i++) add(b[i].x,b[i].d),add(b[i].y+1,-b[i].d);
 88     for(int i=L;i<=R;i++){
 89         if(now[i]>=a[i].k) a[tl++] = a[i]; else a[i].k-=now[i],tmp[tr++] = a[i];
 90     }
 91     for(int i=tl;i<=R;i++) a[i] = tmp[i-tl];
 92     erfn(l,mid,L,tl-1); erfn(mid+1,r,tl,R);
 93 }//
 94 int main()
 95 {    freopen("bzoj4009.in","r",stdin);
 96     freopen("bzoj4009.out","w",stdout);
 97      n=rd(); m=rd(); k=rd();
 98     for(int i=1;i<=n;i++) hd[i]=-1;
 99     for(int i=1;i<n;i++) Adde(rd(),rd());
100     dfsA(1); 
101     dfsB(1,1);
102     for(int i=1,x,y,w;i<=m;i++){
103         x=rd(),y=rd(),w=rd();
104         if(dep[x]<dep[y]) swap(x,y);
105         if(st[x]>=st[y]&&ed[x]<=ed[y]) 
106         {
107         y=find(x,y);
108         e[++tot]=(edge){st[x],ed[x],1,st[y]-1,ed[y]+1,n,w};    
109         }
110         else e[++tot]=(edge){st[x],ed[x],st[y],ed[y],1,0,w};
111     }
112     sort(e+1,e+tot+1);
113     for(int i=1,x,y,w;i<=k;i++){
114         x=rd(),y=rd(),w=rd();
115         a[++cnt]=(A){i,st[x],st[y],w};
116     }
117     erfn(1,tot,1,cnt);
118     for(int i =1;i <= k;i++) printf("%d\n",ans[i]);//
119 }//by tkys_Austin; 

 

 



转载于:https://www.cnblogs.com/Paul-Guderian/p/8689987.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值