HNOI2015接水果--整體二分

題意

給你一棵n 個點的樹和m 條路徑,每條路徑有權值。接下來有q 次詢問,每次再給出一條路徑,詢問這條路徑完全覆蓋的路徑中權值第k 小的路徑權值。

做法

考慮路徑(u,v) 會被哪些路徑完全覆蓋,那麼就有兩種情況:
1、uv 的祖先,那麼完全覆蓋它的路徑(x,y) 滿足dfn[x][1,dfn[w]1][edn[w]+1,n] ,dfn[y][dfn[v],edn[v]] ,其中dfn 表示DFS 序,edn 表示子樹中最大的dfn
2、u 不是v 的祖先,那麼(x,y) 滿足dfn[x][dfn[u],edn[u]] ,dfn[y][dfn[v],edn[v]
可以發現,完全覆蓋這條路徑的點對集合構成了一個或兩個矩形。

算法一

根本不會整體二分,那麼可以把這些矩形按權值從小到大添加進樹套樹,然後詢問的時候二分答案在樹套樹上走一下就可以了。
時間複雜度:O(nlog3n) ,在各大OJ上都是slowest

算法二

每次詢問都是相同的二分,所以可以考慮整體二分,每次二分一個mid 。將(l,mid) 的矩形加進去,同時判斷每個詢問是要往(l,mid) 走還是(mid+1,r) 走,用一個掃描線從左往右掃,每一列用樹狀數組維護就行了。
時間複雜度:O(nlog2n)

代碼

O(nlog3n)

#include<bits/stdc++.h>
using namespace std;
#define REP(i,st,ed) for(int i=(int)(st),i##end=(int)(ed);i<=i##end;++i)
#define DREP(i,st,ed) for(int i=(int)(st),i##end=(int)(ed);i>=i##end;--i)
template<typename T>bool chkmin(T &x,const T &y){return x>y?x=y,1:0;}
template<typename T>bool chkmax(T &x,const T &y){return x<y?x=y,1:0;}
#ifdef __linux__
#define getchar getchar_unlocked
#define putchar putchar_unlocked
#endif
template<typename T>T read(){
    T x=0,f=1;
    char c=getchar();
    while((c<'0')||(c>'9')){if(c=='-')f=-1;c=getchar();}
    while((c>='0')&&(c<='9'))x=(x<<1)+(x<<3)+(c^48),c=getchar();
    return x*f;
}
#define read() read<int>()
template<typename T>void write(T x,char c){
    static char t[25];
    static int tlen;
    t[tlen=1]=c;
    if(x<0)putchar('-'),x=-x;
    do t[++tlen]=(x%10)^48;
    while(x/=10);
    while(tlen)putchar(t[tlen--]);
}
#define pb push_back
typedef long long ll;
typedef double lf;
const int maxn=40005;
struct data{
    int u,v,w;
    bool operator < (const data &A) const {
        return w<A.w;
    }
}q[maxn];
int n,m,q_cnt;
int fa[maxn][16],dep[maxn];
int Root[maxn];
vector<int>E[maxn];
int dfn[maxn],edn[maxn],dfs_clock;
void DFS(int u){
    dfn[u]=++dfs_clock;
    REP(i,0,E[u].size()-1){
        int v=E[u][i];
        if(v==fa[u][0])continue;
        fa[v][0]=u;
        REP(j,1,15)fa[v][j]=fa[fa[v][j-1]][j-1];
        dep[v]=dep[u]+1;
        DFS(v);
    }
    edn[u]=dfs_clock;
}
int lca(int u,int v){
    if(dep[u]<dep[v])swap(u,v);
    DREP(k,15,0)if(dep[fa[u][k]]>=dep[v])u=fa[u][k];
    if(u==v)return u;
    DREP(k,15,0)if(fa[u][k]!=fa[v][k])u=fa[u][k],v=fa[v][k];
    return fa[u][0];
}

int tot;
struct node{int lc,rc,val,tag;};
struct seg_tree{
    node tr[maxn*600];
    void update_y(int &p,int lst,int l,int r,int L,int R,int tag){
        if((!p)||(tr[p].tag!=tag))tr[p=++tot]=tr[lst],tr[p].tag=tag;
        if((L<=l)&&(R>=r)){tr[p].val++;return;}
        int mid=(l+r)>>1;
        if(L<=mid)update_y(tr[p].lc,tr[lst].lc,l,mid,L,R,tag);
        if(R>mid)update_y(tr[p].rc,tr[lst].rc,mid+1,r,L,R,tag);
    }
    void update(int &p,int lst,int l,int r,int L,int R,int L1,int R1,int tag){
        if((!p)||(tr[p].tag!=tag))tr[p=++tot]=tr[lst],tr[p].tag=tag;
        if((L<=l)&&(R>=r))return update_y(tr[p].val,tr[lst].val,1,n,L1,R1,tag);
        int mid=(l+r)>>1;
        if(L<=mid)update(tr[p].lc,tr[lst].lc,l,mid,L,R,L1,R1,tag);
        if(R>mid)update(tr[p].rc,tr[lst].rc,mid+1,r,L,R,L1,R1,tag);
    }
    int query_y(int p,int l,int r,int pos){
        if(!p)return 0;
        int res=tr[p].val;
        if(l==r)return res;
        int mid=(l+r)>>1;
        if(pos<=mid)res+=query_y(tr[p].lc,l,mid,pos);
        else res+=query_y(tr[p].rc,mid+1,r,pos);
        return res;
    }
    int query(int p,int l,int r,int pos,int pos_y){
        if(!p)return 0;
        int res=query_y(tr[p].val,1,n,pos_y);
        if(l==r)return res;
        int mid=(l+r)>>1;
        if(pos<=mid)res+=query(tr[p].lc,l,mid,pos,pos_y);
        else res+=query(tr[p].rc,mid+1,r,pos,pos_y);
        return res;
    }
}T;
int now,lst;
void Update(int L1,int R1,int L2,int R2,int id){
    if((L1>R1)||(L2>R2))return;
    T.update(Root[id],Root[id-1],1,n,L1,R1,L2,R2,id);
    T.update(Root[id],Root[id-1],1,n,L2,R2,L1,R1,id);
}
int Query(int id,int u,int v){
    if(u==v)return T.query(id,1,n,u,v)/2;
    else return T.query(id,1,n,u,v);
}
int find_fa(int u,int dep){
    DREP(k,15,0)if((1<<k)<=dep)u=fa[u][k],dep-=(1<<k);
    return u;
}
int main(){
#ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
    freopen("ans.txt","w",stdout);
#endif
    int u,v,w;
    n=read(),m=read(),q_cnt=read();
    REP(i,1,n-1){
        u=read(),v=read();
        E[u].pb(v),E[v].pb(u);
    }
    dep[1]=1,DFS(1);
    REP(i,1,m){
        u=read(),v=read(),w=read();
        q[i]=(data){u,v,w};
    }
    sort(q+1,q+1+m);
    REP(i,1,m){
        u=q[i].u,v=q[i].v,w=lca(u,v);
        if(dep[u]>dep[v])swap(u,v);
        if(u==w){
            int t=find_fa(v,dep[v]-dep[u]-1);
            Update(dfn[v],edn[v],1,dfn[t]-1,i);
            Update(dfn[v],edn[v],edn[t]+1,n,i);
        }else Update(dfn[u],edn[u],dfn[v],edn[v],i);
    }
    REP(i,1,q_cnt){
        u=read(),v=read(),w=read();
        int l=1,h=m;
        while(l<=h){
            int mid=(l+h)>>1;
            if(Query(Root[mid],dfn[u],dfn[v])>=w)h=mid-1;
            else l=mid+1;
        }write(q[l].w,'\n');
    }
    return 0;
}

O(nlog2n)

#include<bits/stdc++.h>
using namespace std;
#define REP(i,st,ed) for(int i=(int)(st),i##end=(int)(ed);i<=i##end;++i)
#define DREP(i,st,ed) for(int i=(int)(st),i##end=(int)(ed);i>=i##end;--i)
template<typename T>bool chkmin(T &x,const T &y){return x>y?x=y,1:0;}
template<typename T>bool chkmax(T &x,const T &y){return x<y?x=y,1:0;}
#ifdef __linux__
#define getchar getchar_unlocked
#define putchar putchar_unlocked
#endif
template<typename T>T read(){
    T x=0,f=1;
    char c=getchar();
    while((c<'0')||(c>'9')){if(c=='-')f=-1;c=getchar();}
    while((c>='0')&&(c<='9'))x=(x<<1)+(x<<3)+(c^48),c=getchar();
    return x*f;
}
#define read() read<int>()
template<typename T>void write(T x,char c){
    static char t[25];
    static int tlen;
    t[tlen=1]=c;
    if(x<0)putchar('-'),x=-x;
    do t[++tlen]=(x%10)^48;
    while(x/=10);
    while(tlen)putchar(t[tlen--]);
}
#define pb push_back
typedef long long ll;
typedef double lf;
const int maxn=40005;
int n,m,q_cnt;
int fa[maxn][16],dep[maxn];
vector<int>E[maxn];
int dfn[maxn],edn[maxn],dfs_clock;
void DFS(int u){
    dfn[u]=++dfs_clock;
    REP(i,0,E[u].size()-1){
        int v=E[u][i];
        if(v==fa[u][0])continue;
        fa[v][0]=u;
        REP(j,1,15)fa[v][j]=fa[fa[v][j-1]][j-1];
        dep[v]=dep[u]+1;
        DFS(v);
    }
    edn[u]=dfs_clock;
}
int lca(int u,int v){
    if(dep[u]<dep[v])swap(u,v);
    DREP(k,15,0)if(dep[fa[u][k]]>=dep[v])u=fa[u][k];
    if(u==v)return u;
    DREP(k,15,0)if(fa[u][k]!=fa[v][k])u=fa[u][k],v=fa[v][k];
    return fa[u][0];
}
int find_fa(int u,int dep){
    DREP(k,15,0)if((1<<k)<=dep)u=fa[u][k],dep-=(1<<k);
    return u;
}
struct segment{
    int pos,l,r,x;
    bool operator < (const segment &A) const {
        return pos<A.pos;
    }
};
struct data{
    int u,v,w;
    vector<segment>s;
    bool operator < (const data &A) const {
        return w<A.w;
    }
}t[maxn];
struct Query{
    int u,v,k,id,pre;
    bool operator < (const Query &A) const {
        return u<A.u;
    }
}q[maxn],tmp[maxn];
int ans[maxn];
vector<segment>G;
namespace bitree{
    int c[maxn];
    void update(int x,int val){
        while(x<=n)
            c[x]+=val,x+=x&-x;
    }
    int query(int x){
        int res=0;
        while(x)
            res+=c[x],x-=x&-x;
        return res;
    }
}
using namespace bitree;
void solve(int l,int r,int L,int R){
    if((l==r)||(L>R)){
        REP(i,L,R)
            ans[q[i].id]=t[l].w;
        return;
    }
    int mid=(l+r)>>1;
    G.clear();
    REP(i,l,mid)
        REP(j,0,t[i].s.size()-1)G.pb(t[i].s[j]);
    sort(G.begin(),G.end());
    int cur=L,curl=L,curr=R;
    REP(i,0,G.size()-1){
        while((cur<=R)&&(q[cur].u<G[i].pos)){
            int x=query(q[cur].v);
            if(q[cur].pre+x>=q[cur].k)tmp[curl]=q[cur],++curl;
            else tmp[curr]=q[cur],tmp[curr].pre+=x,--curr;
            ++cur;
        }
        update(G[i].l,G[i].x);
        update(G[i].r+1,-G[i].x);
    }
    while(cur<=R){
        int x=query(q[cur].v);
        if(q[cur].pre+x>=q[cur].k)tmp[curl]=q[cur],++curl;
        else tmp[curr]=q[cur],tmp[curr].pre+=x,--curr;
        ++cur;
    }
    REP(i,L,curl-1)q[i]=tmp[i];
    REP(i,curl,R)q[i]=tmp[R-i+curl];
    solve(l,mid,L,curl-1);
    solve(mid+1,r,curl,R);
}
int main(){
#ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
    freopen("out.txt","w",stdout);
#endif
    int u,v,w;
    n=read(),m=read(),q_cnt=read();
    REP(i,1,n-1){
        u=read(),v=read();
        E[u].pb(v),E[v].pb(u);
    }
    dep[1]=1,DFS(1);
    REP(i,1,m){
        u=read(),v=read(),w=read();
        t[i]=(data){u,v,w};
    }
    sort(t+1,t+1+m);
    REP(i,1,m){
        u=t[i].u,v=t[i].v,w=lca(u,v);
        if(dfn[u]>dfn[v])swap(u,v);
        if(u==w){
            w=find_fa(v,dep[v]-dep[u]-1);
            if(dfn[w]>1){
                t[i].s.pb((segment){1,dfn[v],edn[v],1});
                t[i].s.pb((segment){dfn[w],dfn[v],edn[v],-1});
            }
            if(edn[w]<n){
                t[i].s.pb((segment){dfn[v],edn[w]+1,n,1});
                t[i].s.pb((segment){edn[v]+1,edn[w]+1,n,-1});
            }
        }else{
            t[i].s.pb((segment){dfn[u],dfn[v],edn[v],1});
            t[i].s.pb((segment){edn[u]+1,dfn[v],edn[v],-1});
        }
    }
    REP(i,1,q_cnt){
        u=read(),v=read(),w=read();
        if(dfn[u]>dfn[v])swap(u,v);
        q[i]=(Query){dfn[u],dfn[v],w,i};
    }
    sort(q+1,q+1+q_cnt);
    solve(1,m,1,q_cnt);
    REP(i,1,q_cnt)
        write(ans[i],'\n');
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章