【NOI2017模拟6.22】没有上司的舞会

题目大意

只有加点操作,动态维护树的最大独立集

题解

考虑LCT,对于一个点x,s[x][0/1]表示x选或不选时不与他在同一条链上的儿子的DP值,f[x][0/1][0/1]表示splay中x维护的这一个区间最左端选或不选以及最右端选或不选的DP值,只要在切掉splay的边或连接时维护s就好了

代码

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<set>
#include<bitset>
#include<map>

#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)

using namespace std;

typedef long long LL;
typedef double db;

int get(){
    char ch;
    while(ch=getchar(),(ch<'0'||ch>'9')&&ch!='-');
    if (ch=='-'){
        int s=0;
        while(ch=getchar(),ch>='0'&&ch<='9')s=s*10+ch-'0';
        return -s;
    }
    int s=ch-'0';
    while(ch=getchar(),ch>='0'&&ch<='9')s=s*10+ch-'0';
    return s;
}

const int N = 300010;

struct node{
    int s[2];
    int f[2][2];
    int* operator [](int x){return f[x];}
}tree[N];
int fa[N];
int s[N][2];
int n;

int pd(int x){
    if (x==tree[fa[x]].s[0])return 0;
    if (x==tree[fa[x]].s[1])return 1;
    return -1;
}

void update(int x){
    int ls=tree[x].s[0],rs=tree[x].s[1];
    if (!ls&&!rs){
        tree[x][0][1]=tree[x][1][0]=0;
        tree[x][0][0]=s[x][0];
        tree[x][1][1]=s[x][1]+1;
        return;
    }
    if (ls&&rs)
    fo(a,0,1)
        fo(b,0,1)
        tree[x][a][b]=max(tree[ls][a][0]+s[x][1]+tree[rs][0][b]+1,max(tree[ls][a][0],tree[ls][a][1])+s[x][0]+max(tree[rs][0][b],tree[rs][1][b]));
    else
        if (ls){
            fo(a,0,1){
                tree[x][a][1]=tree[ls][a][0]+s[x][1]+1;
                tree[x][a][0]=max(tree[ls][a][0],tree[ls][a][1])+s[x][0];
            }
        }
        else{
            fo(b,0,1){
                tree[x][1][b]=tree[rs][0][b]+s[x][1]+1;
                tree[x][0][b]=s[x][0]+max(tree[rs][0][b],tree[rs][1][b]);
            }
        }
}

void split(int x){
    int y=tree[x].s[1];
    s[x][0]+=max(max(tree[y][0][0],tree[y][0][1]),max(tree[y][1][0],tree[y][1][1]));
    s[x][1]+=max(tree[y][0][0],tree[y][0][1]);
    tree[x].s[1]=0;
    update(x);
}

void merge(int x,int y){
    s[x][0]-=max(max(tree[y][0][0],tree[y][0][1]),max(tree[y][1][0],tree[y][1][1]));
    s[x][1]-=max(tree[y][0][0],tree[y][0][1]);
    tree[x].s[1]=y;
    update(x);
}

void rotate(int x){
    int y=fa[x],z=fa[y];
    int tx=pd(x),ty=pd(y);
    if (ty!=-1)tree[z].s[ty]=x;
    fa[x]=z;
    if (tree[x].s[tx^1])fa[tree[x].s[tx^1]]=y;
    tree[y].s[tx]=tree[x].s[tx^1];
    tree[x].s[tx^1]=y;
    fa[y]=x;
    update(y);
    update(x);
    if (ty!=-1)update(z);
}

void splay(int x){
    while(pd(x)!=-1){
        if (pd(fa[x])!=-1){
            if (pd(fa[x])==pd(x))rotate(fa[x]);
            else rotate(x);
        }
        rotate(x);
    }
}

void access(int x){
    splay(x);
    if (tree[x].s[1])split(x);
    while(fa[x]){
        int y=fa[x];
        splay(y);
        if (tree[y].s[1])split(y);
        merge(y,x);
        update(x);
        x=y;
    }
}

int main(){
    freopen("party.in","r",stdin);
    freopen("party.out","w",stdout);
    n=get();
    int ty=get();
    int ans=0;
    tree[1][1][1]=1;
    tree[1][0][0]=0;
    fo(i,2,n+1){
        int x=get();
        x=x^(ans*ty);
        x++;
        fa[i]=x;
        access(x);
        splay(x);
        tree[i][1][1]=1;
        tree[i][0][0]=0;
        s[x][0]++;
        update(x);
        fo(a,0,1)
            fo(b,0,1)
            ans=max(ans,tree[x][a][b]);
        printf("%d\n",ans);
    }
    fclose(stdin);
    fclose(stdout);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值