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

来源:互联网 发布:外国域名注册机构 编辑:程序博客网 时间:2024/06/05 16:37

题目大意

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

题解

考虑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;}
原创粉丝点击