题目大意

  有一棵树,最开始只有一个点。每次会往这棵树中加一个点,总共\(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. webpack--配置output

    Output output  配置如何输出最终想要的代码. output  是一个  object ,里面包含一系列配置项,下面分别介绍它们. filename output.filename  配置 ...

  2. SPA单页面优缺点

    优点: 1.体验好,不刷新,减少 请求  数据ajax异步获取 页面流程: 2.前后端分离 3.减轻服务端压力 4.共用一套后端程序代码,设配多端 缺点: 1.首屏加载过慢: 2.SEO 不利于搜索引 ...

  3. 把玩Alpine linux(二):APK包管理器

    导读 Alpine Linux非常精简,开机内存占用也在二三十兆大,没有拆箱即用,就需要我们自己去做一些了解和配置 Alpine Linux的优劣 优势 Alpine Linux的Docker镜像特点 ...

  4. nmon for Linux & Java

    nmon for Linux | Main / HomePagehttp://nmon.sourceforge.net/pmwiki.php Java Nmon Analyser download | ...

  5. vsconsole

    一.安装 npm install vconsole 二. if (process.env.NODE_ENV === `development`) { const { logger } = requir ...

  6. MyEclipse 10.X激活方法

    普遍的激活办法请参考: http://blog.csdn.net/miss_kun/article/details/51819206 http://jingyan.baidu.com/article/ ...

  7. Oracle 表空间不足引起的问题及解决方法

    -- 1 向数据库导入数据时报了ORA-01653: unable to extend table错误,网上查了下原因是由于表空间不足引起的: 查询表空间使用情况语句 select a.tablesp ...

  8. [转帖]浏览器的F5和Ctrl+F5

    浏览器的F5和Ctrl+F5 https://www.cnblogs.com/xiangcode/p/5369084.html 在浏览器里中,按F5键和按F5同时按住Ctrl键(简称Ctrl+F5), ...

  9. day 7-9 IO模型

    一,同步和异步,阻塞和非阻塞 同步(synchronous):一个进程在执行某个任务时,另外一个进程必须等待其执行完毕,才能继续执行 #所谓同步,就是在发出一个功能调用时,在没有得到结果之前,该调用就 ...

  10. Kettle中表输出字段和字段选择

    表输出: 字段选择: 注:字段选择可以输出匹配后的选中列,表输出则输出匹配后的所有列.