BZOJ2961:共点圆 圆的反演+cdq分治
BZOJ3611: [Heoi2014]大工程 LCA单调性+树形dp

BZOJ2286: [Sdoi2011]消耗战 LCA单调性+树形dp

shinbokuow posted @ Jan 09, 2015 05:17:27 PM in BZOJ with tags LCA单调性 树形dp , 1217 阅读

思路:

首先对于一次询问进行一次朴素的树形dp极为容易.不过这样需要\(O(n)\)的时间复杂度,这样总的时间复杂度为\(O(qn)\),无法通过.

我们能否对于一次询问,将时间复杂度限定至仅与关键点数有关呢?

 

我们考虑构造一个树结构,仅仅将关键点连接起来,并适当添加部分非关键点,我们如果在这样减缩后的树上做dp,就能使得复杂度只与关键点数有关.

我们利用一个单调栈维护树上的一条深度单调递增的链,当我们要添加的点与栈顶的点的lca深度小于栈顶时,我们不断弹栈并在这个过程中顺便维护此时树的形态.

容易发现,对于每次添加,至多在新树上添加一个点,因此新树的点数只与关键点线性相关.

 

接下来在新树上作朴素的树形dp就行了.

 

#include<cstdio>
#include<cstring>
#include<cctype>
#include<iostream>
#include<algorithm>
using namespace std;
 
namespace Fio{
    inline int getc(){
        static const int L=1<<15;static char buf[L],*S=buf,*T=buf;
        if(S==T){T=(S=buf)+fread(buf,1,L,stdin);if(S==T)return EOF;}
        return*S++;
    }
    template<typename T>inline void Get(T&x){
        int c;while(!isdigit(c=getc())&&c!='-');bool sign=c=='-';
        x=sign?0:c-'0';while(isdigit(c=getc()))x=(x<<1)+(x<<3)+c-'0';
        if(sign)x=-x;
    }
    char buf[5000010],*o=buf;
    template<typename T>inline void print(T x){
        static int stk[100];int top=0;if(x<0)*o++='-',x=-x;
        if(!x)*o++=48;else{for(;x;x/=10)stk[++top]=x%10;for(int i=top;i>=1;--i)*o++=48+stk[i];}
        *o++='\n';
    }
    inline void Final(){fwrite(buf,1,o-buf,stdout);}
}
 
#define N 250010
int head[N],next[N<<1],end[N<<1],len[N<<1];
inline void addedge(int a,int b,int x){
    static int q=1;end[q]=b,next[q]=head[a],len[q]=x,head[a]=q++;
}
inline void make(int a,int b,int x){addedge(a,b,x),addedge(b,a,x);}
 
int pa[N][21],w[N][21],dfn[N],id,dep[N];
void dfs(int x,int fa){
    dfn[x]=++id;
    for(int j=head[x];j;j=next[j])if(end[j]!=fa){
        dep[end[j]]=dep[x]+1,pa[end[j]][0]=x,w[end[j]][0]=len[j],dfs(end[j],x);
    }
}
int lca(int x,int y){
    if(dep[x]<dep[y])swap(x,y);
    for(int i=20;i>=0;--i)if(dep[pa[x][i]]>=dep[y])x=pa[x][i];
    if(x==y)return x;
    for(int i=20;i>=0;--i)if(pa[x][i]!=pa[y][i])x=pa[x][i],y=pa[y][i];
    return pa[x][0];
}
long long calc(int son,int Anc){
    int res=100010;for(int i=20;i>=0;--i)if(dep[pa[son][i]]>=dep[Anc])res=min(res,w[son][i]),son=pa[son][i];return res;
}
 
int seq[N],siz;
 
inline bool cmp(const int&a,const int&b){return dfn[a]<dfn[b];}
 
int stk[N],top,Anc[N];
 
struct Array{
    long long sum[N];int t[N];
    inline void modify(int x,int add,int v){
        if(t[x]!=v)t[x]=v,sum[x]=0;sum[x]+=add;
    }
    inline long long ask(int x,int v){
        if(t[x]!=v)t[x]=v,sum[x]=0;return sum[x];
    }
}f,IsImp;int nowv;
 
int main(){
    #ifndef ONLINE_JUDGE
    freopen("tt.in","r",stdin);
    #endif
    using namespace Fio;
    int n;Fio::Get(n);
    register int i,j;int a,b,x;for(i=1;i<n;++i)Get(a),Get(b),Get(x),make(a,b,x);
    dep[1]=1,dfs(1,-1);
    for(j=1;j<=20;++j)
        for(i=1;i<=n;++i)pa[i][j]=pa[pa[i][j-1]][j-1],w[i][j]=min(w[i][j-1],w[pa[i][j-1]][j-1]);
    int Q;Get(Q);
    while(Q--){
        Get(siz);for(i=1;i<=siz;++i)Get(seq[i]);++nowv;for(i=1;i<=siz;++i)IsImp.modify(seq[i],1,nowv);seq[++siz]=1;
        sort(seq+1,seq+siz+1,cmp);int end=siz;
        for(top=0,i=1;i<=siz;++i){
            if(!top)stk[++top]=seq[i];
            else{
                int Lca=lca(stk[top],seq[i]);Anc[seq[i]]=Lca;
                while(dep[stk[top]]>dep[Lca]){if(dep[stk[top-1]]<=dep[Lca])Anc[stk[top]]=Lca;--top;}
                if(stk[top]!=Lca)Anc[Lca]=stk[top],seq[++end]=stk[++top]=Lca;
                stk[++top]=seq[i];
            }
        }
        sort(seq+1,seq+end+1,cmp);
        //for(i=1;i<=siz;++i)printf("%d ",seq[i]);puts("");
        long long dis;
        for(i=end;i>=1;--i){
            dis=calc(seq[i],Anc[seq[i]]);
            if(IsImp.ask(seq[i],nowv))f.modify(Anc[seq[i]],dis,nowv);else f.modify(Anc[seq[i]],min(dis,f.ask(seq[i],nowv)),nowv);
        }
        print(f.ask(1,nowv));
    }
    return Final(),0;
}


登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter