1. 程式人生 > >Red Black Tree ZOJ

Red Black Tree ZOJ

比賽時思路很普通 隊友按二分寫的 無限TLE 複雜度還是太高

每個黑點的花費只和最近的紅點祖先有關 並且一次查詢中只取最大值 利用這個特點 對查詢的點按花費降序排序 記為p1>p2>...>pk 若要使最終答案小於等於pi 那選擇變紅的點必須是[1,i]這些點的lca才行 因為如果不想辦法把這些點的花費減小 答案肯定不會小於等於pi 所有掃一遍並不斷求lca即可

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2e5+10;

struct node
{
    ll w;
    int v,next;
};

node edge[2*maxn];
ll dis[maxn];
int dp[maxn][20];
int first[maxn],book[maxn],deep[maxn],red[maxn],pre[maxn];
int n,m,q,num;

bool cmp(int u,int v)
{
    return dis[u]-dis[red[u]]>dis[v]-dis[red[v]];
}

void addedge(int u,int v,ll w)
{
    edge[num].v=v;
    edge[num].w=w;
    edge[num].next=first[u];
    first[u]=num++;
}

void dfs(int cur,int fa,int anc)
{
    ll w;
    int i,v;
    for(i=first[cur];i!=-1;i=edge[i].next){
        v=edge[i].v,w=edge[i].w;
        if(v!=fa){
            dp[v][0]=cur;
            deep[v]=deep[cur]+1,dis[v]=dis[cur]+w;
            if(book[v]){
                red[v]=v;
                dfs(v,cur,v);
            }
            else{
                red[v]=anc;
                dfs(v,cur,anc);
            }
        }
    }
}

void init()
{
    int i,j;
    dp[1][0]=0;
    deep[1]=1,dis[1]=0;
    red[1]=1;
    dfs(1,0,1);
    for(j=1;(1<<j)<=n;j++){
        for(i=1;i<=n;i++){
            dp[i][j]=dp[dp[i][j-1]][j-1];
        }
    }
}

int getlca(int u,int v)
{
    int i;
    if(deep[u]<deep[v]) swap(u,v);
    for(i=log2(n);i>=0;i--){
        if(deep[dp[u][i]]>=deep[v]) u=dp[u][i];
    }
    if(u==v) return u;
    for(i=log2(n);i>=0;i--){
        if(dp[u][i]!=dp[v][i]) u=dp[u][i],v=dp[v][i];
    }
    return dp[u][0];
}

int main()
{
    ll w,ans,res1,res2,preval,val;
    int t,i,j,k,u,v,prelca,lca;
    scanf("%d",&t);
    while(t--){
        scanf("%d%d%d",&n,&m,&q);
        memset(first,-1,sizeof(first));
        memset(book,0,sizeof(book));
        num=0;
        for(i=1;i<=m;i++){
            scanf("%d",&u);
            book[u]=1;
        }
        for(i=1;i<=n-1;i++){
            scanf("%d%d%lld",&u,&v,&w);
            addedge(u,v,w),addedge(v,u,w);
        }
        init();
        while(q--)
        {
            scanf("%d",&k);
            for(i=1,j=0;i<=k;i++){
                scanf("%d",&u);
                if(!book[u]) pre[++j]=u;
            }
            k=j;
            if(k<=1) printf("0\n");
            else{
                sort(pre+1,pre+k+1,cmp);
                ans=dis[pre[2]]-dis[red[pre[2]]],preval=0;
                prelca=pre[1];
                for(i=1;i<=k;i++){
                    lca=getlca(prelca,pre[i]);
                    res1=preval+dis[prelca]-dis[lca];
                    res2=min(dis[pre[i]]-dis[red[pre[i]]],dis[pre[i]]-dis[lca]);
                    val=max(res1,res2);
                    if(i+1<=k) ans=min(ans,max(val,dis[pre[i+1]]-dis[red[pre[i+1]]]));
                    else ans=min(ans,val);
                    prelca=lca,preval=val;
                }
                printf("%lld\n", ans);
            }
        }
    }
    return 0;
}