zoukankan      html  css  js  c++  java
  • HDU5331 : Simple Problem

    因为是二分图,所以最大独立集$=$总点数$-$最大匹配。

    因为是树,所以具有贪心性质,设$f_i$表示$i$是否与其孩子匹配,$a_i$表示$i$的孩子里$f$为$0$的个数,则$f_i=[a_i>0]$。

    加入一个新的叶子的时候,影响的$a$是连续的一段,这一段上与它距离为奇数的点的$a$都要是$0$,距离为偶数的点都要是$1$。

    树链剖分+线段树维护即可。

    时间复杂度$O(nlog^2n)$。

    #include<cstdio>
    const int N=100010,M=262150;
    int n,i,y,f[N],g[N],nxt[N],d[N],size[N],son[N],loc[N],top[N],q[N],dfn;
    int len[M],v[M],mx[M][2],tag[M][2],rev[M];
    inline void read(int&a){char c;while(!(((c=getchar())>='0')&&(c<='9')));a=c-'0';while(((c=getchar())>='0')&&(c<='9'))(a*=10)+=c-'0';}
    void dfs(int x){
      size[x]=1;
      for(int i=g[x];i;i=nxt[i]){
        d[i]=d[x]+1;
        dfs(i),size[x]+=size[i];
        if(size[i]>size[son[x]])son[x]=i;
      }
    }
    void dfs2(int x,int y){
      q[loc[x]=++dfn]=x;top[x]=y;
      if(son[x])dfs2(son[x],y);
      for(int i=g[x];i;i=nxt[i])if(i!=son[x])dfs2(i,i);
    }
    inline int max(int a,int b){return a>b?a:b;}
    inline void tag1(int o,int x,int p){mx[x][o]+=p;tag[x][o]+=p;}
    inline void rev1(int x){v[x]=len[x]-v[x];rev[x]^=1;}
    inline void pb(int x){
      for(int o=0;o<2;o++)if(tag[x][o])tag1(o,x<<1,tag[x][o]),tag1(o,x<<1|1,tag[x][o]),tag[x][o]=0;
      if(rev[x])rev1(x<<1),rev1(x<<1|1),rev[x]=0;
    }
    inline void up(int x){
      v[x]=v[x<<1]+v[x<<1|1];
      for(int o=0;o<2;o++)mx[x][o]=max(mx[x<<1][o],mx[x<<1|1][o]);
    }
    void build(int x,int a,int b){
      len[x]=b-a+1;v[x]=rev[x]=0;
      for(int o=0;o<2;o++)mx[x][o]=tag[x][o]=0;
      if(a==b)return;
      int mid=(a+b)>>1;
      build(x<<1,a,mid),build(x<<1|1,mid+1,b);
    }
    void ask(int x,int a,int b,int c,int d,int o){
      if(c<=a&&b<=d){
        if(mx[x][o]<=1&&mx[x][o^1]<=0){y=a;return;}
        if(a==b){if(!y)y=N;return;}
      }
      pb(x);
      int mid=(a+b)>>1;
      if(d>mid){
        ask(x<<1|1,mid+1,b,c,d,o);
        if(y>mid+1)return;
      }
      if(c<=mid)ask(x<<1,a,mid,c,d,o);
    }
    void change(int x,int a,int b,int c,int d,int o){
      if(c<=a&&b<=d){tag1(o,x,-1);tag1(o^1,x,1);return;}
      pb(x);
      int mid=(a+b)>>1;
      if(c<=mid)change(x<<1,a,mid,c,d,o);
      if(d>mid)change(x<<1|1,mid+1,b,c,d,o);
      up(x);
    }
    void reverse(int x,int a,int b,int c,int d){
      if(c<=a&&b<=d){rev1(x);return;}
      pb(x);
      int mid=(a+b)>>1;
      if(c<=mid)reverse(x<<1,a,mid,c,d);
      if(d>mid)reverse(x<<1|1,mid+1,b,c,d);
      up(x);
    }
    inline void modify(int x,int o){
      for(;x;x=f[top[x]]){
        y=0;
        ask(1,1,n,loc[top[x]],loc[x],o);
        if(y<N)y=q[y];
        if(y==N){
          change(1,1,n,loc[x],loc[x],o);
          return;
        }
        change(1,1,n,loc[y],loc[x],o);
        reverse(1,1,n,loc[y],loc[x]);
        if(y!=top[x]){
          y=f[y];
          change(1,1,n,loc[y],loc[y],o);
          return;
        }
      }
    }
    int main(){
      while(~scanf("%d",&n)){
        for(dfn=0,i=1;i<=n;i++)g[i]=son[i]=0;
        for(i=2;i<=n;i++){
          read(f[i]),f[i]++;
          nxt[i]=g[f[i]],g[f[i]]=i;
        }
        dfs(1),dfs2(1,1),build(1,1,n);
        for(i=2;i<=n;i++)modify(f[i],d[i]&1),printf("%d
    ",i-v[1]);
      }
      return 0;
    }
    

      

  • 相关阅读:
    通过C#的HttpClient模拟form表单请求
    通过Mysql连接ASP.Net Core2.0(Code First模式)
    每天一点产品思考(1):微博是否可以尝试取消点赞数展示?
    Google Analytics 学习笔记四 —— GA的Channels划分规则
    Google Analytics 学习笔记三 —— GA常用术语
    Google Analytics 学习笔记二 —— GA部署
    Google Analytics 学习笔记一 —— GA简介
    java基础知识总结(一)
    java源码解析之String类(二)
    java源码解析之String类(一)
  • 原文地址:https://www.cnblogs.com/clrs97/p/5922295.html
Copyright © 2011-2022 走看看