Codechef August Challenge 2018 : Chef at the River
(要是没有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的更多相关文章
- Codechef August Challenge 2018 : Safe Partition
传送门 (虽然是A了但是不知道复杂度是不是正确的 考虑以某个位置为结尾的合法划分 先考虑min,带来的影响是限制了最小长度,预处理出这个最小长度后,这可以在处理到这个数时,把不能算的部分去掉(不满足m ...
- Codechef August Challenge 2018 : Interactive Matrix
传送门 首先整个矩阵可以被分为很多小矩阵,小矩阵内所有行的单调性是一样的,所有列的单调性是一样的. 考虑如何在这样一个小矩阵中找出答案.我的策略是每次取四个角中最大值和最小值的点,这样可以每次删掉一行 ...
- Codechef August Challenge 2018 : Lonely Cycles
传送门 几波树形dp就行了. #include<cstdio> #include<cstring> #include<algorithm> #define MN 5 ...
- Codechef August Challenge 2018 : Coordinate Compression
传送门 外边二分,里面拿线段树维护贪心就行了. #include<cstdio> #include<vector> #include<cstring> #inclu ...
- Codechef August Challenge 2018 : Modular GCD
传送门 一开始还手动拓欧找规律,发现好像玩不了. 然后想了想,A-B这个数比较小,枚举它的因子判断合不合法就行了. 需要特判A=B的情况. #include<cstdio> #includ ...
- 【线段树 泰勒展开】Codechef April Challenge 2018 Chef at the Food Fair
第一次写泰勒展开:本地和CC差距好大 题目大意 大厨住的城市里办了一场美食节.一条街上开设了$N$个摊位,编号为$1∼N$.这天开始时,第$i$个摊位的食物会导致食物中毒的概率是$P_i$.在这一天中 ...
- Codechef August Challenge 2019 Chef and Gordon Ramsay
[传送门] 题目即求所有的三元组,相对大小关系同 $p_1,p_2,p_3$. 题解说都很清楚,这里写一下过程整理一下思路. 如果我们枚举中间这个元素,那么就是统计子树内外有多少个大于这个数和小于这个 ...
- Codechef October Challenge 2018 游记
Codechef October Challenge 2018 游记 CHSERVE - Chef and Serves 题目大意: 乒乓球比赛中,双方每累计得两分就会交换一次发球权. 不过,大厨和小 ...
- Codechef September Challenge 2018 游记
Codechef September Challenge 2018 游记 Magician versus Chef 题目大意: 有一排\(n(n\le10^5)\)个格子,一开始硬币在第\(x\)个格 ...
随机推荐
- saltstack主机管理项目:动态调用插件解析-模块解析(五)
一.动态调用插件解析 1.目录结构 1.base_module代码解析: def syntax_parser(self,section_name,mod_name,mod_data): print(& ...
- 【Java面试题】19 final,finally和finalize的区别
总体区别 final 用于申明属性,方法和类,表示属性不可变,方法不可以被覆盖,类不可以被继承.finally 是异常处理语句结构中,表示总是执行的部分. finallize ...
- GIT-Bonobo.Git.Server的使用
GIT-Bonobo.Git.Server的使用 登录 (默认用户:admin/admin) 创建用户: 创建团队,勾选用户 创建新库 保存完成!
- 深入学习css伪类和伪元素及其用法
前言 CSS的伪类和伪元素在平时的代码中经常会出现,可是一旦别人问你,什么是伪类,什么是伪元素,可能还是不能完整的表述出来,下面我们来一探究竟. 伪类和伪元素定义 伪类用于在页面中的元素处于某个状态时 ...
- js 计算当年还剩多少时间的倒数计时 javascript 原理解析【复制到编辑器查看推荐】
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- CentOS/Linux开放某些端口
CentOS/Linux开放某些端口 CentOS/Linux 装载系统的时候只开启了少数端口如22,80(有些连80都没有开放)等. 结果再装完Nginx+PHP+MySQL 后不能访问网站. 当然 ...
- Element老司机开车了
orm Select选择器 坑: 1.选择器视图层一直渲染最后一个元素(value-key作为唯一标识符是关键)2.视图不更新,没有在data函数中声明变量,或者其他地方重置了已经声明过得变量 o ...
- 设计模式九: 观察者模式(Observer Pattern)
简介 观察者属于行为型模式的一种, 又叫发布-订阅模式. 如果一个对象的状态发生改变,依赖他的对象都将发生变化, 那么这种情况就适合使用观察者模式. 它包含两个术语,主题(Subject),观察者(O ...
- [转] Python 字符编码判断
转自:http://www.cnblogs.com/dkblog/archive/2011/03/02/1980644.html 法一: isinstance(s, str) 用来判断是否为一般字符串 ...
- CDQ分治求不知道多少维偏序 (持续更新 ]
求三维偏序的模板 : //Author : 15owzLy1 //luogu3810.cpp //2018 12 25 16:31:58 #include <cstdio> #includ ...