传送门

(要是没有tjm(Sakits)的帮忙,我还真不知道啥时候能做出来

结论是第一次带走尽可能少的动物,使未带走的动物不冲突,带走的这个数量就是最优解。

首先这个数量肯定是下界,更少的话连第一次都带不走。

然后考虑带过去之后把某一只留在对岸,剩下的全部随身携带,这时有了一个空位,就可以慢慢把与留下的动物无关联的都挪到对岸去。再把随身携带的动物中与未到达对岸的任何一只都无关联的动物留着,其余的(包括之前单出来的)随身携带,这时有了一个空位可以再次慢慢挪。

唯一的特殊情况是某一个点连接了剩余所有点,且总点数大于3,特判即可。

接着是如何计算第一次最少带多少只的问题。

取父亲必定不比取儿子差,我们可以维护这个贪心,这样就只有一种解。

考虑某次多了一个点,肯定是从这个点往上某条链的状态取反,这条链延伸的终点必定是一个已取的点有其他未取的儿子。

树剖之后维护每个点未取的轻儿子的个数,每次查询需要在线段树上二分一下。虽然看起来是两个log,但是明显跑不满,可以A(水)掉。

#include<cstdio>
#include<algorithm>
#define MN 1100000
#define lp p<<1
#define rp p<<1|1
using namespace std; int n,T,f[MN],_s[MN],l[MN],num,df[MN],lo[MN],s[MN],nm,son[MN],to[MN],ANS,t[MN<<],Z[MN<<],c[MN],w[MN],st[MN];
bool b[MN<<];
inline int max(int x,int y){return x>y?x:y;}
inline int min(int x,int y){return x<y?x:y;}
struct na{int y,ne;}B[MN<<];
inline void add(int x,int y){B[++num].y=y;B[num].ne=l[x];l[x]=num;}
void dfs(int x){
s[x]=;son[x]=;
for (int i=l[x];i;i=B[i].ne) if (dfs(B[i].y),s[x]+=s[B[i].y],s[B[i].y]>s[son[x]]) son[x]=B[i].y;
}
void DFS(int x,int q){
df[x]=++nm;to[x]=q;
if (son[x]) DFS(son[x],q);
for (int i=l[x];i;i=B[i].ne)
if (B[i].y!=son[x]) DFS(B[i].y,B[i].y);
lo[x]=nm;
}
inline void rev(int p){
b[p]^=;
}
inline void pd(int p,int l,int r){
if (b[p])
if (b[p]=,l!=r) rev(lp),rev(rp);
else c[l]^=;
}
void fz(int p,int l,int r,int L,int R){
if (l==L&&r==R) {rev(p);return;}
pd(p,l,r);
int mid=l+r>>;
if (R<=mid) fz(lp,l,mid,L,R);else
if (L>mid) fz(rp,mid+,r,L,R);else
fz(lp,l,mid,L,mid),fz(rp,mid+,r,mid+,R);
}
int ask(int p,int l,int r,int L,int R){
//printf("%d %d %d %d %d %d %d %d\n",p,l,r,L,R,t[p],t[lp],t[rp]);
if (!t[p]) return ;
if (l==L&&r==R) return Z[p];
pd(p,l,r);
int mid=l+r>>,tmp;
if (R<=mid) return ask(lp,l,mid,L,R);else
if (L>mid) return ask(rp,mid+,r,L,R);else
if (tmp=ask(rp,mid+,r,mid+,R)) return tmp;else return ask(lp,l,mid,L,mid);
}
bool col(int p,int l,int r,int k){
pd(p,l,r);
if (l==r) return c[k];
int mid=l+r>>;
if (k<=mid) return col(lp,l,mid,k);else return col(rp,mid+,r,k);
}
void ADD(int p,int l,int r,int k,int v){
t[p]+=v;
if (l==r){
Z[p]=t[p]?l:;
return;
}
int mid=l+r>>;
if (k<=mid) ADD(lp,l,mid,k,v);else ADD(rp,mid+,r,k,v);
if (t[p]) if (t[rp]) Z[p]=Z[rp];else Z[p]=Z[lp];else Z[p]=;
}
inline void work(int x){
int tmp,top=,la=;
while (x){
if (son[x]&&col(,,n,df[x]+)) break;
if (tmp=ask(,,n,df[to[x]],df[x])){
if (tmp!=df[x]) fz(,,n,tmp+,df[x]),la=tmp+;
break;
}
//printf("===%d %d\n",x,tmp);
fz(,,n,df[to[x]],df[x]);
la=df[to[x]];
if (f[to[x]]){
if (col(,,n,df[to[x]])){
st[++top]=f[to[x]];
}else if (--w[f[to[x]]]==) ADD(,,n,df[f[to[x]]],-);
}
x=f[to[x]];
}
while (top){
if (w[st[top]]++==) ADD(,,n,df[st[top]],);
top--;
}
ANS+=!col(,,n,la);
//printf("la:%d %d\n",la,col(1,1,n,la));
//for (int j=1;j<=n;j++) printf("col %d %d:%d\n",j,df[j],col(1,1,n,df[j]));
}
int main(){
scanf("%d",&T);
while(T--){
scanf("%d",&n);
for (int i=;i<=n;i++) _s[i]=l[i]=s[i]=son[i]=c[i]=w[i]=to[i]=;num=nm=ANS=;
for (int i=;i<=(n<<);i++) t[i]=b[i]=Z[i]=;
for (int i=;i<=n;i++){
scanf("%d",&f[i]);
add(f[i],i);
}
dfs();
DFS(,);
work();
for (int i=;i<=n;i++){
_s[f[i]]++;
work(i);
printf("%d ",ANS++((_s[]==i-&&i>||_s[]==&&_s[]==i-&&i>)));
//printf("%d\n",ANS);
}
puts("");
}
}

Codechef August Challenge 2018 : Chef at the River的更多相关文章

  1. Codechef August Challenge 2018 : Safe Partition

    传送门 (虽然是A了但是不知道复杂度是不是正确的 考虑以某个位置为结尾的合法划分 先考虑min,带来的影响是限制了最小长度,预处理出这个最小长度后,这可以在处理到这个数时,把不能算的部分去掉(不满足m ...

  2. Codechef August Challenge 2018 : Interactive Matrix

    传送门 首先整个矩阵可以被分为很多小矩阵,小矩阵内所有行的单调性是一样的,所有列的单调性是一样的. 考虑如何在这样一个小矩阵中找出答案.我的策略是每次取四个角中最大值和最小值的点,这样可以每次删掉一行 ...

  3. Codechef August Challenge 2018 : Lonely Cycles

    传送门 几波树形dp就行了. #include<cstdio> #include<cstring> #include<algorithm> #define MN 5 ...

  4. Codechef August Challenge 2018 : Coordinate Compression

    传送门 外边二分,里面拿线段树维护贪心就行了. #include<cstdio> #include<vector> #include<cstring> #inclu ...

  5. Codechef August Challenge 2018 : Modular GCD

    传送门 一开始还手动拓欧找规律,发现好像玩不了. 然后想了想,A-B这个数比较小,枚举它的因子判断合不合法就行了. 需要特判A=B的情况. #include<cstdio> #includ ...

  6. 【线段树 泰勒展开】Codechef April Challenge 2018 Chef at the Food Fair

    第一次写泰勒展开:本地和CC差距好大 题目大意 大厨住的城市里办了一场美食节.一条街上开设了$N$个摊位,编号为$1∼N$.这天开始时,第$i$个摊位的食物会导致食物中毒的概率是$P_i$.在这一天中 ...

  7. Codechef August Challenge 2019 Chef and Gordon Ramsay

    [传送门] 题目即求所有的三元组,相对大小关系同 $p_1,p_2,p_3$. 题解说都很清楚,这里写一下过程整理一下思路. 如果我们枚举中间这个元素,那么就是统计子树内外有多少个大于这个数和小于这个 ...

  8. Codechef October Challenge 2018 游记

    Codechef October Challenge 2018 游记 CHSERVE - Chef and Serves 题目大意: 乒乓球比赛中,双方每累计得两分就会交换一次发球权. 不过,大厨和小 ...

  9. Codechef September Challenge 2018 游记

    Codechef September Challenge 2018 游记 Magician versus Chef 题目大意: 有一排\(n(n\le10^5)\)个格子,一开始硬币在第\(x\)个格 ...

随机推荐

  1. 在鼠标右键上加入使用notepad++编辑【转】

    我们在安装完notepad++文本编辑器之后,在一个文本文件上右键有时候并没有出现“使用notepad++编辑的选项”,我们可以通过简单地修改注册表文件来增加这样的功能: 1.  首先打开注册表,wi ...

  2. 第六节: 六类Calander处理六种不同的时间场景

    背景介绍及其使用 该章节主要补充介绍,在前一章四类触发器的基础上配合六大Canlander来动态删减某些时间,来满足更多的应用场景. 1. DailyCalendar:动态排除某天的某些字段. (需求 ...

  3. MarkDown 的两种页内跳转方法!!!!!

    页面内跳转就是点击某个文本,能够跳转到页面里指定的其他地方,经常用于目录中. 第一种是利用Html5 比如点击Feature, 跳转到features中 MarkDown: [Feature](#1) ...

  4. 2.11 while循环的嵌套以及应用(难)

    while循环嵌套 前面学习过if的嵌套了,想一想if嵌套是什么样子的? 类似if的嵌套,while嵌套就是:while里面还有while <1>while嵌套的格式 while 条件1: ...

  5. Android Studio项目Gradle内网配置

    由于内网无法连接到外部网络,在使用Gradle编译Android Studio项目时就会面临一些问题: 1.Gradle安装文件无法下载 2.Gradle Android插件无法下载 3.项目依赖文件 ...

  6. C# 微信开发-----微信会员卡(三)激活会员卡

    在会员领取了会员卡之后需要做 一个跳转性激活,模式请看下图: 在创建会员卡的时候需要配置下这个参数的值: memberActivate.aspx页面代码如下: <%@ Page Language ...

  7. iOS -- Effective Objective-C 阅读笔记 (6)

    1: 在 既有类中使用 关联对象存放自定义数据 有时候需要在对象中存放相关信息, 这是我们经常会从对象所属的类中继承一个子类, 然后改用这个子类对象, 然而并非所有的情况下都能这么做,  有时候类的实 ...

  8. ES6新语法

    ES6新语法概览 简介 ES6是JavaScript语言的新一代标准,加入了一些新的功能和语法,正式发布于2015年6月,亦称ES2015:该标准由ECMA(欧洲计算机制造联合会)的第39号技术专家委 ...

  9. YII 自封装的批量修改的mysql操作类

    <?php /** * Created by PhpStorm. * User: yufen * Date: 2018/8/31 * Time: 9:54 */ namespace app\ba ...

  10. iOS开发之微信平台分享

    在工程开始之前应该先准备在微信开放平台申请的appid,从微信平台下载sdk文件.下面开始步骤讲述 1.先将SDK导入工程目录 2.在info.plist文件设置相关信息,包括appid标识.白名单 ...