1. 程式人生 > >BZOJ4009 & 洛谷3242 & LOJ2113:[HNOI2015]接水果——題解

BZOJ4009 & 洛谷3242 & LOJ2113:[HNOI2015]接水果——題解

getchar() .html black target str 解調 noi2015 != --

https://www.lydsy.com/JudgeOnline/problem.php?id=4009

https://www.luogu.org/problemnew/show/P3242

https://loj.ac/problem/2113

風見幽香非常喜歡玩一個叫做 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 小的那個盤子,每個盤子可重復使用(沒有使用次數的上限:一個盤子接完一個水果後,後面還可繼續接其他水果,只要它是水果路徑的子路徑)。幽香認為這個遊戲很難,你能輕松解決給她看嗎?

技術分享圖片

因為預先做過LOJ6276:果樹,不難想到對於樹上路徑的處理方法和它一樣。

那麽對於每個盤子用dfs序表示的路徑點(u,v),分兩種情況:

1.u和v有一個不同於二者的lca

顯然它能接到的水果的兩端一個在u的子樹中,一個在v的子樹中。

2.v是u的祖先。

顯然它能接到的水果的兩端一個在u的子樹中,一個在v的子樹的補集(包括v)中。

那麽對於一個水果的路徑點,如果在這個矩形當中,就說明這個水果能夠被哪些盤子所接。

那麽處理完之後,顯然不能用主席樹來解決第k大(如果能當我沒說),於是我們整體二分一下即可。

……這是我最開始做這道題的想法,但是碼了4h後對此絕望,對著數據參著題解調到現在才過。

說幾個(我)容易錯的點:

1.區間第k小,所以不是第k大的做法,註意答案在左區間還是右區間。

2.用掃描線存的時候註意空間開大點,另外上邊界不要忘了+1

代碼138行湊和吧,但是細節真心多。

#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=4e4+5;
const int B=17;
inline int read(){
    int X=0,w=0;char ch=0;
    while(!isdigit(ch)){w|=ch==-;ch=getchar();}
    while(isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
    return w?-X:X;
}
struct path{
    int to,nxt;
}e[N*2];
struct dish{
    int x1,x2,y,c,w;
}d[4*N],td1[4*N],td2[4*N];
struct fruit{
    int x,y,k,id;
}f[N],tf1[N],tf2[N];
int m,b[N],ans[N],tr[N],c[N];
int anc[N][B+4],dep[N],size[N];
int n,p,q,cnt,head[N],pos[N],tot;
inline bool cmp1(dish a,dish b){
    return a.y<b.y;
}
inline bool cmp2(fruit a,fruit b){
    return a.y<b.y;
}
inline void add(int u,int v){
    e[++cnt].to=v;e[cnt].nxt=head[u];head[u]=cnt;
}
void dfs(int u){
    pos[u]=++tot;size[u]=1;
    dep[u]=dep[anc[u][0]]+1;
    for(int i=1;i<=B;++i)
        anc[u][i]=anc[anc[u][i-1]][i-1];
    for(int i=head[u];i;i=e[i].nxt){
        int v=e[i].to;
        if(v!=anc[u][0]){
            anc[v][0]=u;
            dfs(v);
            size[u]+=size[v];
        }
    }
}
inline int LCA(int i,int j){
    if(dep[i]<dep[j])swap(i,j);
    for(int k=B;k>=0;--k)
        if(dep[anc[i][k]]>=dep[j])i=anc[i][k];
    if(i==j)return i;
    for(int k=B;k>=0;--k)
        if(anc[i][k]!=anc[j][k])
            i=anc[i][k],j=anc[j][k];
    return anc[i][0];
}
inline int lowbit(int t){return t&(-t);}
inline void ins(int x,int y){
    for(int i=x;i<=n;i+=lowbit(i))tr[i]+=y;
}
inline int qry(int x){
    int res=0;
    for(int i=x;i;i-=lowbit(i))res+=tr[i];
    return res;
}
inline void mdy(int l,int r,int w){
    ins(l,w);ins(r+1,-w);
}
void solve(int L,int R,int s,int t,int l,int r){
    if(L>R||s>t)return;
    if(l==r){
        for(int i=L;i<=R;++i)ans[f[i].id]=c[l];
        return;
    }
    int id1=0,id2=0,if1=0,if2=0,mid=(l+r)>>1,j=s;
    for(int i=L;i<=R;++i){
        for(;j<=t&&d[j].y<=f[i].y;++j){
            if(d[j].c>c[mid])td1[id1++]=d[j];
            else mdy(d[j].x1,d[j].x2,d[j].w),td2[id2++]=d[j];
        }
        int tmp=qry(f[i].x);
        if(f[i].k>tmp)f[i].k-=tmp,tf1[if1++]=f[i];
        else tf2[if2++]=f[i];
    }
    for(;j<=t;++j){
        if(d[j].c>c[mid])td1[id1++]=d[j];
        else mdy(d[j].x1,d[j].x2,d[j].w),td2[id2++]=d[j];
    }
    int mdst=s+id1,MID=L+if1;
    for(int i=s;i<mdst;++i)d[i]=td1[i-s];
    for(int i=mdst;i<=t;++i)d[i]=td2[i-mdst];
    for(int i=L;i<MID;++i)f[i]=tf1[i-L];
    for(int i=MID;i<=R;++i)f[i]=tf2[i-MID];
    solve(L,MID-1,s,mdst-1,mid+1,r);solve(MID,R,mdst,t,l,mid);
    return;
}
int main(){
    n=read(),p=read(),q=read();
    for(int i=1;i<n;++i){
        int u=read(),v=read();
        add(u,v);add(v,u);
    }
    dfs(1);
    for(int i=1;i<=p;++i){
        int u=read(),v=read();c[i]=read();
        if(pos[u]>pos[v])swap(u,v);
        int lca=LCA(u,v);
        if(lca!=u&&lca!=v){
            d[++m]=(dish){pos[u],pos[u]+size[u]-1,pos[v],c[i],1};
            d[++m]=(dish){pos[u],pos[u]+size[u]-1,pos[v]+size[v],c[i],-1};
        }else{
            int t=v;
            for(int k=B;k>=0;--k)
                if(dep[anc[t][k]]>=dep[u]+1)t=anc[t][k];
            d[++m]=(dish){1,pos[t]-1,pos[v],c[i],1};
            d[++m]=(dish){1,pos[t]-1,pos[v]+size[v],c[i],-1};
            d[++m]=(dish){pos[v],pos[v]+size[v]-1,pos[t]+size[t],c[i],1};
            d[++m]=(dish){pos[v],pos[v]+size[v]-1,n+1,c[i],-1};
        }
    }
    for(int i=1;i<=q;++i){
        int u=read(),v=read(),k=read();
        if(pos[u]>pos[v])swap(u,v);
        f[i]=(fruit){pos[u],pos[v],k,i};
    }
    sort(d+1,d+m+1,cmp1);
    sort(f+1,f+q+1,cmp2);
    sort(c+1,c+p+1);
    int len=unique(c+1,c+p+1)-c-1;
    solve(1,q,1,m,1,len);
    for(int i=1;i<=q;++i)printf("%d\n",ans[i]);
    return 0;
}

+++++++++++++++++++++++++++++++++++++++++++

+本文作者:luyouqi233。               +

+歡迎訪問我的博客:http://www.cnblogs.com/luyouqi233/+

+++++++++++++++++++++++++++++++++++++++++++

BZOJ4009 & 洛谷3242 & LOJ2113:[HNOI2015]接水果——題解