zoukankan      html  css  js  c++  java
  • 【Luogu】P2495消耗战(虚树DP)

      题目链接

      我虚树没很理解啊qwq

      就是我们有比较少的询问点,然后我们把不需要考虑的点搞一搞扔掉,然后每次询问给那些询问点单独建一颗树,然后乱搞。

      ……好吧看来是完全没理解……

      链接大法qwq

      

    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    #include<cctype>
    #define maxn 500000
    using namespace std;
    inline long long read(){
        long long num=0,f=1;
        char ch=getchar();
        while(!isdigit(ch)){
            if(ch=='-')    f=-1;
            ch=getchar();
        }
        while(isdigit(ch)){
            num=num*10+ch-'0';
            ch=getchar();
        }
        return num*f;
    }
    
    struct Edge{
        int next,to,val;
    }edge[maxn*2];
    int head[maxn],num;
    inline void add(int from,int to,int val){
        edge[++num]=(Edge){head[from],to,val};
        head[from]=num;
    }
    
    int stack[maxn],top;
    int deep[maxn];
    int s[maxn][22];
    int dfn[maxn],ID;
    int q[maxn];
    long long f[maxn];
    long long ans[maxn];
    bool flag[maxn];
    
    void dfs(int x,int fa){
        deep[x]=deep[fa]+1;    dfn[x]=++ID;
        for(int i=head[x];i;i=edge[i].next){
            int to=edge[i].to;
            if(to==fa)    continue;
            s[to][0]=x;
            f[to]=min(f[x],(long long)edge[i].val);
            dfs(to,x);
        }
        return;
    }
    
    bool cmp(int a,int b){    return dfn[a]<dfn[b];    }
    
    int calclca(int a,int b){
        if(deep[a]<deep[b])    swap(a,b);
        int f=deep[a]-deep[b];
        for(int i=0;1<<i<=f;++i)
            if(f&(1<<i))    a=s[a][i];
        if(a==b)    return a;
        for(int i=20;i>=0;--i){
            if(s[a][i]==s[b][i])    continue;
            a=s[a][i];b=s[b][i];
        }
        return s[a][0];
    }
    
    void calc(int x,int fa){
        long long sum=0;
        ans[x]=f[x];
        for(int i=head[x];i;i=edge[i].next){
            int to=edge[i].to;
            if(to==fa)    continue;
            calc(to,x);
            sum+=ans[to];
        }
        if(sum&&!flag[x])    ans[x]=min(ans[x],sum);
        head[x]=0;
        return;
    }
    
    int main(){
        f[1]=1e9;    f[1]=f[1]*f[1];
        int n=read();
        for(int i=1;i<n;++i){
            int from=read(),to=read(),val=read();
            add(from,to,val);
            add(to,from,val);
        }
        dfs(1,1);
        for(int i=1;i<=20;++i)
            for(int j=1;j<=n;++j)
                s[j][i]=s[s[j][i-1]][i-1];
        int m=read();
        memset(head,0,sizeof(head));
        for(int i=1;i<=m;++i){
            num=0;top=0;
            int x=read();    
            for(int j=1;j<=x;++j){    q[j]=read();flag[q[j]]=1;    }
            sort(q+1,q+x+1,cmp);
            for(int j=1;j<=x;++j){
                if(top==0){
                    stack[++top]=q[j];
                    continue;
                }
                int lca=calclca(q[j],stack[top]);
                while(dfn[lca]<dfn[stack[top]]){
                    if(dfn[lca]>=dfn[stack[top-1]]){
                        add(lca,stack[top],0);
                        if(stack[--top]!=lca)    stack[++top]=lca;
                        break;
                    }
                    add(stack[top-1],stack[top],0);
                    top--;
                }
                stack[++top]=q[j];
            }
            while(top>1){
                add(stack[top-1],stack[top],0);
                top--;
            }
            calc(stack[1],stack[1]);
            printf("%lld
    ",ans[stack[1]]);
            for(int j=1;j<=x;++j)    flag[q[j]]=0;
        }
        return 0;
    }
  • 相关阅读:
    FFOM_秒交易行
    FFOM_脚本源代码
    农药_挂周金币
    保存数据,父页面列表数据更新
    点击按钮不弹出新窗口
    GridView1_RowDeleting 弹出确认对话框
    判断复选框
    获取Guid
    2019 gplt团体程序设计天梯赛总结
    Codeforces Round #550 (Div. 3)E. Median String
  • 原文地址:https://www.cnblogs.com/cellular-automaton/p/8256759.html
Copyright © 2011-2022 走看看