题目大意

  有一棵树,最开始只有一个点。每次会往这棵树中加一个点,总共\(n\)次。输出每次加点后树的最大独立集大小。

  强制在线。

  \(n\leq 300000\)

题解

  显然是LCT。

  那么要维护什么呢?

  先看看DP方程:设\(f_{i,0}\)为以\(i\)为根的子树中\(i\)这个点不选的答案,\(f_{i,1}\)为\(i\)这个点选的答案。显然

\[\begin{align}
f_{i,0}&=\sum_{v}\max(f_{v,0},f_{v,1})\\
f_{i,1}&=1+\sum_v f_{v,0}
\end{align}
\]

  先看看一条链要怎么做。设\(s_{i,j}\)为某一段中第一个点的状态为\(i\),在后面补一个状态为\(j\)的点时这一段的贡献。这个东西很容易合并。

  只有一个点时

\[\begin{align}
s_{0,0}&=0\\
s_{0,1}&=0\\
s_{1,0}&=1\\
s_{1,1}&=-\infty
\end{align}
\]

  那树上要怎么做?

  容易观察到\(i\)的各个儿子之间是互不影响的。可以像这道题一样,把整棵树剖成轻重链,每个点的贡献要加上这个点的轻儿子的贡献。

  access和link时处理一下即可。

  时间复杂度:\(O(n\log n)\)

题解

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<ctime>
#include<utility>
#include<cmath>
#include<functional>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
void sort(int &a,int &b)
{
if(a>b)
swap(a,b);
}
void open(const char *s)
{
#ifndef ONLINE_JUDGE
char str[100];
sprintf(str,"%s.in",s);
freopen(str,"r",stdin);
sprintf(str,"%s.out",s);
freopen(str,"w",stdout);
#endif
}
int rd()
{
int s=0,c;
while((c=getchar())<'0'||c>'9');
do
{
s=s*10+c-'0';
}
while((c=getchar())>='0'&&c<='9');
return s;
}
void put(int x)
{
if(!x)
{
putchar('0');
return;
}
static int c[20];
int t=0;
while(x)
{
c[++t]=x%10;
x/=10;
}
while(t)
putchar(c[t--]+'0');
}
int upmin(int &a,int b)
{
if(b<a)
{
a=b;
return 1;
}
return 0;
}
int upmax(int &a,int b)
{
if(b>a)
{
a=b;
return 1;
}
return 0;
}
struct p
{
ll s11,s12,s21,s22;
p()
{
s11=s12=s21=s22=0;
}
};
p merge(p a,p b)
{
p c;
c.s11=max(a.s11+b.s11,a.s12+b.s21);
c.s12=max(a.s11+b.s12,a.s12+b.s22);
c.s21=max(a.s21+b.s11,a.s22+b.s21);
c.s22=max(a.s21+b.s12,a.s22+b.s22);
return c;
}
void add(p &a,ll s11,ll s12,ll s21,ll s22)
{
a.s11+=s11;
a.s12+=s12;
a.s21+=s21;
a.s22+=s22;
}
namespace lct
{
int f[300010];
int a[300010][2];
p v[300010];
p s[300010];
int root(int x)
{
return !f[x]||(a[f[x]][0]!=x&&a[f[x]][1]!=x);
}
void mt(int x)
{
s[x]=v[x];
if(a[x][0])
s[x]=merge(s[a[x][0]],s[x]);
if(a[x][1])
s[x]=merge(s[x],s[a[x][1]]);
}
void rotate(int x)
{
int p=f[x];
int q=f[p];
int ps=(x==a[p][1]);
int qs=(p==a[q][1]);
int ch=a[x][ps^1];
if(!root(p))
a[q][qs]=x;
a[x][ps^1]=p;
a[p][ps]=ch;
if(ch)
f[ch]=p;
f[p]=x;
f[x]=q;
mt(p);
}
void splay(int x)
{
while(!root(x))
{
int p=f[x];
if(!root(p))
{
int q=f[p];
if((p==a[q][1])==(x==a[p][1]))
rotate(p);
else
rotate(x);
}
rotate(x);
}
mt(x);
}
void access(int x)
{
int y=x;
int t=0;
while(x)
{
splay(x);
add(v[x],max(s[a[x][1]].s21,s[a[x][1]].s22),max(s[a[x][1]].s21,s[a[x][1]].s22),max(max(s[a[x][1]].s11,s[a[x][1]].s12),max(s[a[x][1]].s21,s[a[x][1]].s22)),max(max(s[a[x][1]].s11,s[a[x][1]].s12),max(s[a[x][1]].s21,s[a[x][1]].s22)));
add(v[x],-max(s[t].s21,s[t].s22),-max(s[t].s21,s[t].s22),-max(max(s[t].s11,s[t].s12),max(s[t].s21,s[t].s22)),-max(max(s[t].s11,s[t].s12),max(s[t].s21,s[t].s22)));
a[x][1]=t;
mt(x);
t=x;
x=f[x];
}
splay(y);
}
void link(int x,int y)
{
v[x].s11=-0x7fffffff;
v[x].s12=1;
v[x].s21=0;
v[x].s22=0;
mt(x);
access(y);
f[x]=y;
a[y][1]=x;
// add(v[y],1,0);
mt(y);
}
};
int main()
{
open("b");
int n,type;
scanf("%d%d",&n,&type);
int i,x;
int ans=0;
lct::v[1].s11=-0x7fffffff;
lct::v[1].s12=1;
lct::v[1].s21=0;
lct::v[1].s22=0;
lct::mt(1);
for(i=2;i<=n+1;i++)
{
scanf("%d",&x);
if(type)
x^=ans;
x++;
lct::link(i,x);
lct::access(1);
ans=max(max(lct::s[1].s11,lct::s[1].s21),max(lct::s[1].s12,lct::s[1].s22));
printf("%d\n",ans);
}
return 0;
}

【XSY2665】没有上司的舞会 LCT DP的更多相关文章

  1. 『没有上司的舞会 树形DP』

    树形DP入门 有些时候,我们需要在树形结构上进行动态规划来求解最优解. 例如,给定一颗\(N\)个节点的树(通常是无根树,即有\(N-1\)条无向边),我们可以选择任意节点作为根节点从而定义出每一颗子 ...

  2. 洛谷P1352 没有上司的舞会——树形DP

    第一次自己写树形DP的题,发个博客纪念`- 题目来源:P1352 没有上司的舞会 题目描述 某大学有N个职员,编号为1~N.他们之间有从属关系,也就是说他们的关系就像一棵以校长为根的树,父结点就是子结 ...

  3. CodeVS1380 没有上司的舞会 [树形DP]

    题目传送门 没有上司的舞会 题目描述 Description Ural大学有N个职员,编号为1~N.他们有从属关系,也就是说他们的关系就像一棵以校长为根的树,父结点就是子结点的直接上司.每个职员有一个 ...

  4. P1352 没有上司的舞会——树形DP入门

    P1352 没有上司的舞会 题目描述 某大学有N个职员,编号为1~N.他们之间有从属关系,也就是说他们的关系就像一棵以校长为根的树,父结点就是子结点的直接上司.现在有个周年庆宴会,宴会每邀请来一个职员 ...

  5. wikioi 1380 没有上司的舞会 树形dp

    1380 没有上司的舞会 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond       题目描述 Description Ural大学有N个职员,编号为1~N.他 ...

  6. [luogu]P1352 没有上司的舞会[树形DP]

    本Lowbee第一次写树形DP啊,弱...一个变量写错半天没看出来...... 题目描述 某大学有N个职员,编号为1~N.他们之间有从属关系,也就是说他们的关系就像一棵以校长为根的树,父结点就是子结点 ...

  7. 没有上司的舞会 树形dp

    题目描述 某大学有N个职员,编号为1~N.他们之间有从属关系,也就是说他们的关系就像一棵以校长为根的树,父结点就是子结点的直接上司.现在有个周年庆宴会,宴会每邀请来一个职员都会增加一定的快乐指数Ri, ...

  8. P1352 没有上司的舞会[树形dp]

    题目描述 某大学有N个职员,编号为1~N.他们之间有从属关系,也就是说他们的关系就像一棵以校长为根的树,父结点就是子结点的直接上司.现在有个周年庆宴会,宴会每邀请来一个职员都会增加一定的快乐指数Ri, ...

  9. P1352 没有上司的舞会&&树形DP入门

    https://www.luogu.com.cn/problem/P1352 题目描述 某大学有N个职员,编号为1~N.他们之间有从属关系,也就是说他们的关系就像一棵以校长为根的树,父结点就是子结点的 ...

随机推荐

  1. Jvm 参数笔记

    Jvm参数含义 https://cloud.tencent.com/developer/article/1129474 从一道题说起 https://blog.csdn.net/crazylzxlzx ...

  2. 牛客---java练习

    一. 1. abstract可以修饰方法和类,不能修饰属性.抽象方法没有方法体,即没有大括号{}.抽象类中的成员属性都是public static final类型的:成员方法都是public abst ...

  3. [LeetCode] Department Highest Salary -- 数据库知识(mysql)

    184. Department Highest Salary The Employee table holds all employees. Every employee has an Id, a s ...

  4. 软件工程启程篇章:C#和四则运算生成与运算

    0x01 :序言 I leave uncultivated today, was precisely yestoday perishes tomorrow which the person of th ...

  5. Day10 Python基础之特殊函数(八)

    一些特殊函数 1.递归函数(recursion) 递归函数的定义:在函数内部,可以调用其他函数.如果一个函数在内部调用自身本身,这个函数就是递归函数. 递归函数的优点:是定义简单,逻辑清晰.理论上,所 ...

  6. servlet程序HTTP Status 500 - Error instantiating servlet class 解决

    在eclipase 中编译 servlet  但是一致报 HTTP Status 500 - Error instantiating servlet class XXX类 的问题 , 解决方法 1. ...

  7. VMware威睿

    VMware总部位于美国加州帕洛阿尔托 [1]  ,是全球云基础架构和移动商务解决方案厂商,提供基于VMware的解决方案, 企业通过数据中心改造和公有云整合业务,借助企业安全转型维系客户信任 [2- ...

  8. HTML 5 Web 音频

    HTML 5 音频http://www.w3school.com.cn/html5/html_5_audio.asp 在 Web 上播放音频http://www.w3school.com.cn/med ...

  9. rem移动端适配方案

    一. rem vs em 单位 定义 特点 rem font size of the root element 以根元素字体大小为基准 em font size of the element 以父元素 ...

  10. 【面试】MySQL的事务和索引

    MySQL事务 MySQL事务主要用于处理操作量大,复杂度高的数据. 比如说,在人员管理系统中,你删除一个人员,你既需要删除人员的基本资料,也要删除和该人员相关的信息,如信箱,文章等等,这些数据库操作 ...