接水果(fruit)
接水果(fruit)
風(fēng)見幽香非常喜歡玩一個叫做 osu! 的游戲,其中她最喜歡玩的模式就是接水果。由于她已經(jīng) DT FC 了 The big black,她覺得這個游戲太簡單了,于是發(fā)明了一個更加難的版本。
首先有一個地圖,是一棵由 $n$ 個頂點、$n-1$ 條邊組成的樹(例如圖 $1$ 給出的樹包含 $8$ 個頂點、$7$ 條邊)。這顆樹上有 P 個盤子,每個盤子實際上是一條路徑(例如圖 $1$ 中頂點 $6$ 到頂點 $8$ 的路徑),并且每個盤子還有一個權(quán)值。第 $i$ 個盤子就是頂點 $a_i$ 到頂點 $b_i$ 的路徑(由于是樹,所以從 $a_i$ 到 $b_i$ 的路徑是唯一的),權(quán)值為 $c_i$。接下來依次會有 $Q$ 個水果掉下來,每個水果本質(zhì)上也是一條路徑,第 $i$ 個水果是從頂點 $u_i$ 到頂點 $v_i$ 的路徑。
幽香每次需要選擇一個盤子去接當(dāng)前的水果:一個盤子能接住一個水果,當(dāng)且僅當(dāng)盤子的路徑是水果的路徑的子路徑(例如圖 $1$ 中從 $3$ 到 $7$ 的路徑是從 $1$ 到 $8$ 的路徑的子路徑)。這里規(guī)定:從 $a$ 到 $b$ 的路徑與從 $b$ 到 $a$ 的路徑是同一條路徑。當(dāng)然為了提高難度,對于第 $i$ 個水果,你需要選擇能接住它的所有盤子中,權(quán)值第 $k_i$ 小的那個盤子,每個盤子可重復(fù)使用(沒有使用次數(shù)的上限:一個盤子接完一個水果后,后面還可繼續(xù)接其他水果,只要它是水果路徑的子路徑)。幽香認(rèn)為這個游戲很難,你能輕松解決給她看嗎?
solution
這題真的奇怪:盤子比水果小才接的到,,,
考慮一個盤子,他的兩端u,v
如果一個一個水果的兩端在u,v的子樹以內(nèi),那么他就是可以被接到的
求出dfs序,把這個水果的兩個端點映射到平面上,就變成點要在矩形內(nèi)的限制。
于是問題轉(zhuǎn)化為求覆蓋一個點的第k大矩形。
限制有3維,考慮整體二分。
先按x排序,y用掃描線,把權(quán)值拿去整體二分。
具體實現(xiàn):
當(dāng)前二分權(quán)值v,加入<=mid的所有矩形,查詢每個點覆蓋他的矩形有幾個。
如果大于限制就扔l-mid,否則扔mid=1-r,并且把限制減去當(dāng)前答案。
盤子對應(yīng)矩形是分下類:
u v不互為祖先就是直接的兩段連續(xù)dfs序
假設(shè)深度較大的子樹是u,深度較小的子樹是v。v這條鏈上的兒子是k
u 仍是dfs序,并上k在整棵樹的補集。
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<map>
#define maxn 320005
using namespace std;
int n,P,Q,head[maxn],tot,sc,dft[maxn],dfn[maxn];
int deep[maxn],f[maxn][22],top,Max,q[maxn],ans[maxn];
int tr[maxn],tx[maxn],tp,cnt,dy[maxn];
map<int,int>ls;
struct node{
int v,nex;
}e[maxn*2];
struct sq{
int fl,pl,a,b,v,val;
}a[maxn],b[maxn];
void lj(int t1,int t2){
e[++tot].v=t2;e[tot].nex=head[t1];head[t1]=tot;
}
void dfs(int k,int fa){
dft[k]=++sc;deep[k]=deep[fa]+1;f[k][0]=fa;
for(int i=head[k];i;i=e[i].nex){
if(e[i].v!=fa)dfs(e[i].v,k);
}
dfn[k]=sc;
}
int Lca(int u,int v){
if(deep[u]<deep[v])swap(u,v);
for(int x=20;x>=0;x--)if(deep[f[u][x]]>=deep[v])u=f[u][x];
for(int x=20;x>=0;x--)if(f[u][x]!=f[u][x])u=f[u][x],v=f[v][x];
return u==v?u:f[u][0];
}
bool cmp(sq a,sq b){
return a.pl<b.pl||(a.pl==b.pl&&a.fl<b.fl);
}
void add(int i,int v){
for(;i<=n;i+=i&-i)tr[i]+=v;
}
int ask(int i){
int sum=0;
for(;i;i-=i&-i)sum+=tr[i];
return sum;
}
void add(int xa,int xb,int ya,int yb,int w){
if(xa>xb||ya>yb||ya<0||xa<0)return;
a[++top]=(sq){0,xa,ya,yb,w,1};
a[++top]=(sq){0,xb+1,ya,yb,w,-1};
}
void lsh(){
sort(tx+1,tx+tp+1);
cnt=0;
for(int i=1;i<=tp;i++)
if(!ls[tx[i]])ls[tx[i]]=++cnt,dy[cnt]=tx[i];
}
void solve(int l,int r,int ql,int qr){
if(ql>qr)return;
if(l==r){
for(int i=ql;i<=qr;i++){
if(a[i].fl>0)ans[a[i].fl]=l;
}
return;
}
int mid=l+r>>1;
for(int i=ql;i<=qr;i++){
if(a[i].fl>0){
q[i]=ask(a[i].a);
}
else {
if(a[i].v<=mid){
add(a[i].a,a[i].val);add(a[i].b+1,-a[i].val);
}
}
}
for(int i=ql;i<=qr;i++){
if(a[i].fl==0){
if(a[i].v<=mid){
add(a[i].a,-a[i].val);add(a[i].b+1,a[i].val);
}
}
}
int t=ql-1;
for(int i=ql;i<=qr;i++){
if(a[i].fl>0){
if(q[i]>=a[i].v)b[++t]=a[i];
}
else {
if(a[i].v<=mid)b[++t]=a[i];
}
}
int ff=t;
for(int i=ql;i<=qr;i++){
if(a[i].fl>0){
if(q[i]<a[i].v){
a[i].v-=q[i];
b[++t]=a[i];
}
}
else {
if(a[i].v>mid)b[++t]=a[i];
}
}
for(int i=ql;i<=qr;i++)a[i]=b[i];
solve(l,mid,ql,ff);solve(mid+1,r,ff+1,qr);
}
int main()
{
cin>>n>>P>>Q;
for(int i=1,t1,t2;i<n;i++){
scanf("%d%d",&t1,&t2);
lj(t1,t2);lj(t2,t1);
}
dfs(1,0);
for(int j=1;j<=20;j++)
for(int i=1;i<=n;i++)f[i][j]=f[f[i][j-1]][j-1];
for(int i=1,u,v,w;i<=P;i++){
scanf("%d%d%d",&u,&v,&w);
tx[++tp]=w;
if(deep[u]<deep[v])swap(u,v);
int lca=Lca(u,v);
if(lca==v){
int dep=deep[u]-deep[v]-1;
int t=u;
for(int x=20;x>=0;x--){
if((1<<x)<=dep){
t=f[t][x];dep-=(1<<x);
}
}
add(dft[u],dfn[u],1,dft[t]-1,w);
add(1,dft[t]-1,dft[u],dfn[u],w);
add(dft[u],dfn[u],dfn[t]+1,n,w);
add(dfn[t]+1,dft[u],dfn[u],n,w);
}
else {
add(dft[u],dfn[u],dft[v],dfn[v],w);
add(dft[v],dfn[v],dft[u],dfn[u],w);
}
}
lsh();
for(int i=1,t1,t2,t3;i<=Q;i++){
scanf("%d%d%d",&t1,&t2,&t3);
a[++top].fl=i;
a[top].pl=dft[t2];a[top].a=dft[t1];a[top].v=t3;
}
sort(a+1,a+top+1,cmp);
for(int i=1;i<=top;i++){
if(!a[i].fl)a[i].v=ls[a[i].v];
}
solve(1,cnt,1,top);
for(int i=1;i<=Q;i++){
printf("%d
",dy[ans[i]]);
}
return 0;
}
View Code
總結(jié)
以上是生活随笔為你收集整理的接水果(fruit)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 两个路由器冲突怎么办几台路由器冲突如何解
- 下一篇: 微信聊天记录怎么备份到电脑如何将手机微信