zoukankan      html  css  js  c++  java
  • CodeChef

    https://www.codechef.com/problems/BLACKCOM

    题意:一颗5000个黑白结点的树,10W个查询寻找是否存在大小s并且有t和黑节点的子图

    一开始就觉得应当是一个树dp,但是总觉得怎么做怎么超时,用dp[5000][5000]预处理s大小t结点的可行性在时间复杂度上并不合理。

    但是这题有一个结论,对于树上一个大小为s的子图而言,如果同时有可以存在r个黑色节点和l个黑色节点,则l - r之间的所有黑色节点都可以构造。

    有了这个结论,就可以把dp方程转变为t结点的子树下大小为s最多的黑色和最少的黑色,然后取他们之间的值即可。

    细节在于子树之间的处理,dfs的时候同一颗子树是不能将子图加起来的,需要另开一个数组更新当前子树对答案的更新结果,最后统一赋值给最终答案。

    #include <map>
    #include <set>
    #include <ctime>
    #include <cmath>
    #include <queue>
    #include <stack>
    #include <vector>
    #include <string>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <sstream>
    #include <iostream>
    #include <algorithm>
    #include <functional>
    using namespace std;
    inline int read(){int now=0;register char c=getchar();for(;!isdigit(c);c=getchar());
    for(;isdigit(c);now=now*10+c-'0',c=getchar());return now;}
    #define For(i, x, y) for(int i=x;i<=y;i++)  
    #define _For(i, x, y) for(int i=x;i>=y;i--)
    #define Mem(f, x) memset(f,x,sizeof(f))  
    #define Sca(x) scanf("%d", &x)
    #define Sca2(x,y) scanf("%d%d",&x,&y)
    #define Sca3(x,y,z) scanf("%d%d%d",&x,&y,&z)
    #define Scl(x) scanf("%lld",&x);  
    #define Pri(x) printf("%d
    ", x)
    #define Prl(x) printf("%lld
    ",x);  
    #define CLR(u) for(int i=0;i<=N;i++)u[i].clear();
    #define LL long long
    #define ULL unsigned long long  
    #define mp make_pair
    #define PII pair<int,int>
    #define PIL pair<int,long long>
    #define PLL pair<long long,long long>
    #define pb push_back
    #define fi first
    #define se second 
    typedef vector<int> VI;
    const double eps = 1e-9;
    const int maxn = 5e3 + 10;
    const int INF = 0x3f3f3f3f;
    const int mod = 1e9 + 7; 
    int N,M,K;
    struct Edge{
        int to,next;
    }edge[maxn * 2];
    int head[maxn],tot;
    void init(){
        for(int i = 1; i <= N ; i ++) head[i] = -1;
        tot = 0;
    }
    void add(int u,int v){
        edge[tot].to = v;
        edge[tot].next = head[u];
        head[u] = tot++;
    }
    int color[maxn];
    int MAX[maxn][maxn],MIN[maxn][maxn];
    int oMAX[maxn][maxn],oMIN[maxn][maxn];
    int L[maxn],R[maxn],size[maxn];
    void dfs(int t,int la){
        MAX[t][1] = MIN[t][1] = color[t];
        size[t] = 1;
        for(int i = head[t]; ~i; i = edge[i].next){
            int v = edge[i].to;
            if(v == la) continue;
            dfs(v,t);
            for(int j = 1; j <= size[t] + size[v]; j ++){
                oMIN[t][j] = INF; oMAX[t][j] = 0;
            }
            for(int p = 0; p <= size[v]; p ++){
                for(int q = 1; q <= size[t]; q ++){
                    oMAX[t][p + q] = max(MAX[t][q] + MAX[v][p],oMAX[t][p + q]);
                    oMIN[t][p + q] = min(MIN[t][q] + MIN[v][p],oMIN[t][p + q]);
                }
            }
            size[t] += size[v];
            for(int p = 1; p <= size[t]; p ++){
                MAX[t][p] = oMAX[t][p];
                MIN[t][p] = oMIN[t][p];
            }
        }
        for(int i = 1; i <= size[t]; i ++){
            L[i] = min(L[i],MIN[t][i]);
            R[i] = max(R[i],MAX[t][i]);
        }
    } 
    int main(){
        int T; Sca(T);
        while(T--){
            Sca2(N,M);init();
            for(int i = 1; i <= N - 1; i ++){
                int u,v; Sca2(u,v);
                add(u,v); add(v,u);
            }
            for(int i = 1; i <= N ; i ++){
                L[i] = INF; R[i] = -INF;
            }
            for(int i = 1; i <= N ; i ++) Sca(color[i]);
            dfs(1,-1);
            for(int i = 1; i <= M ; i ++){
                int u,v; Sca2(u,v);
                if(L[u] <= v && v <= R[u]) puts("Yes");
                else puts("No");
            }
        }
        return 0;
    }
  • 相关阅读:
    第一阶段个人总结02
    第二阶段冲刺第十天
    第二阶段冲刺第九天
    第二阶段冲刺第八天
    第二阶段冲刺第七天
    第二阶段冲刺第六天
    第二阶段冲刺第五天
    第二阶段冲刺第四天
    第十六周总结
    第二阶段冲刺第三天
  • 原文地址:https://www.cnblogs.com/Hugh-Locke/p/10280607.html
Copyright © 2011-2022 走看看