• 题解 P6753 【[BalticOI 2013 Day1] Ball Machine】


    题解 P6753 【[BalticOI 2013 Day1] Ball Machine】

    考试硬生生做了 3h....

    一个没找出性质的菜鸡。。。

    整个思路就是 模拟,但是带有优化

    算法:倍增+重链剖分+线段树

    对于 1 操作:

    可以知道当一个球放在 x 上时,一定是将 x 的子树都放满后再放的 x ,

    因为他的儿子是有放的先后之分的,

    所以考虑记录下最小编号的路径,再在这条路径上倍增

    那么整个一操作就可以分为下面三步:

    假设答案为 (now)

    1.从 (now) 倍增跳到最小路径上 dep 最大的点上,使得这个点的子树(包括他自己)的可放置空间 $>= num $

    (now)赋成这个点

    2.扫描 (now) 的所有出边(按照路径最小编号最小到大,这个可以通过一次树形DP处理出扫描顺序),

    如果这个出点 (y) 的可放置位置 (<num),那么 (num-y)子树内剩余的位置,并且将整个 (y) 子树的子树变成 1

    如果可放置位置(>=num)的话,直接使 now=y,并且 break;

    3.一直重复这个过程,直到找到一个点使得它的可放置空间 (= num)

    最后输出 这个点的编号

    那么难点就来了,如何快速查找这个点可放置个数?

    答案就是轻重链剖分,只需要

    query(seg[x],seg[x]+size[x]-1)
    

    就可以获得整个子树有多少个位置已经放置过,

    size[x]-query(seg[x],seg[x]+size[x]-1)
    

    就可以快速算出可放置位置了

    复杂度(O(log^2n))(看起来常数有点大,但是跑的飞快)

    对于 2 操作

    很容易想到,这个操作就是从这个点向根走,有多少个连续的 1 。将连续的1的个数 -1(减去自己)就是答案

    最后将最上面的 1 删除就好了,这个用树剖就很好判断了.

    复杂度因为有一个线段树,所以还是(O(log^2n))

    这道题的细节如果用这个思路的话好多啊。。。

    整体复杂度:(O(n log^2n))

    一开始一个树形DP (O(n))

    对于一个点 x ,将 x 能到达的点按照这个点的子树最小值从小到大排序,因为一条边只会多出一个点,所以这个复杂度就是(O(n log n))

    倍增复杂度也为(O(n log n))

    Code:

    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    #define lc x<<1
    #define rc x<<1|1
    const int N=1e5+5,Q=1e5+5,LOG=18;
    template <typename T>
    inline void read(T &x){
    	x=0;char ch=getchar();bool f=false;
    	while(!isdigit(ch)){f^=ch=='-';ch=getchar();}
    	while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch-'0');ch=getchar();}
    	x=f?-x:x;
    }
    template <typename T>
    inline void print(T x){
    	if(x<0){putchar('-');x=-x; }
    	if(x>9){print(x/10);}
    	putchar(x%10+48);
    }
    int head[N],to[N],minn[N],Next[N],tot,n,q,root;
    int fson[LOG][N],len[N];
    int dep[N],fa[N],siz[N],son[N];
    vector<pair<int,int> > edge[N];
    inline bool cmp(pair<int,int> x,pair<int,int> y){return x.first<y.first;}
    inline void add(int u,int v){to[++tot]=v;Next[tot]=head[u],head[u]=tot;}
    inline void dfs1(int x,int f){
    	dep[x]=dep[f]+1;siz[x]=1;fa[x]=f;minn[x]=x;
    	for(register int i=head[x];i;i=Next[i]){
    		int y=to[i];
    		dfs1(y,x);
    		siz[x]+=siz[y];minn[x]=min(minn[x],minn[y]);
    		edge[x].push_back(make_pair(minn[y],y));
    		if(siz[y]>siz[son[x]]){son[x]=y;}
    	}
    }
    int top[N],seg[N],rev[N],dnt;
    inline void dfs2(int x){
    	top[x]=son[fa[x]]==x? top[fa[x]] : x;
    	len[top[x]]++;
    	seg[x]=++dnt;rev[dnt]=x;
    	if(son[x]){dfs2(son[x]);}
    	for(register int i=head[x];i;i=Next[i]){
    		int y=to[i];
    		if(y!=son[x]){dfs2(y);}
    	}
    }
    struct seg_tree{
    	int l,r,sum,lazy;
    	#define l(x)	c[x].l
    	#define r(x)	c[x].r
    	#define sum(x)	c[x].sum
    	#define lazy(x)	c[x].lazy
    }c[N<<2];
    inline void update(int x){sum(x)=sum(lc)+sum(rc);}
    inline void build(int x,int l,int r){
    	l(x)=l,r(x)=r;
    	if(l==r){return;}
    	int mid=(l+r)>>1;
    	build(lc,l,mid);
    	build(rc,mid+1,r);
    	return;
    }
    inline void change(int x,int d){sum(x)=(r(x)-l(x)+1);lazy(x)=1;}
    inline void push_down(int x){if(lazy(x)){change(lc,lazy(x));change(rc,lazy(x));lazy(x)=0;}}
    inline void modify_1(int x,int l,int r,int d){
    	if(l(x)>=l&&r(x)<=r){change(x,d);return;}
    	push_down(x);
    	int mid=(l(x)+r(x))>>1;
    	if(mid>=l){modify_1(lc,l,r,d);}
    	if(mid<r){modify_1(rc,l,r,d);}
    	update(x);
    	return;
    }
    inline void modify_2(int x,int l,int d){
    	if(l(x)==r(x)){sum(x)+=d;return;}
    	push_down(x);
    	int mid=(l(x)+r(x))>>1;
    	if(mid>=l){modify_2(lc,l,d);}
    	else{modify_2(rc,l,d);}
    	update(x);
    	return;
    }
    inline int query(int x,int l,int r){
    	if(l(x)>=l&&r(x)<=r){return sum(x);}
    	push_down(x);
    	int mid=(l(x)+r(x))>>1;
    	int res=0;
    	if(mid>=l){res+=query(lc,l,r);}
    	if(mid<r){res+=query(rc,l,r);}
    	return res;
    }
    inline int uptoroot(int x){
    	int res=0,tep=0,last=0;
    	while(top[x]!=root){
    		tep=query(1,seg[top[x]],seg[x]);
    		if(tep==seg[x]-seg[top[x]]+1){
    			res+=tep;
    			last=top[x];
    			x=fa[top[x]];
    		}
    		else{break;}
    	}
    	tep=query(1,seg[top[x]],seg[x]);
    	if(tep==0){modify_2(1,seg[last],-1);}
    	else{res+=tep;modify_2(1,seg[x]-tep+1,-1);}
    	return res-1;
    }
    int main(){
    	read(n),read(q);
    	for(register int i=1;i<=n;++i){
    		int u;read(u);
    		if(!u){root=i;}
    		else{add(u,i);}
    	}
    	dfs1(root,0);
    	dfs2(root);
    	int lim=log2(n)+1;
    	for(register int i=1;i<=n;++i){
    		sort(edge[i].begin(),edge[i].end(),cmp);
    		if(!edge[i].empty())	fson[0][i]=edge[i][0].second;
    	}
    	for(register int j=1;j<=lim;++j){for(register int i=1;i<=n;++i){fson[j][i]=fson[j-1][fson[j-1][i]];}}
    	build(1,1,n);
    	while(q--){
    		int op,num;
    		read(op),read(num);
    		if(op==1){
    			bool flag=false;
    			int teproot=root;
    			int now=teproot;
    			while(!flag){
    				now=teproot;
    				if(siz[now]-query(1,seg[now],seg[now]+siz[now]-1)==num){flag=true;break;}
    				for(register int i=lim;i>=0;--i){
    					int y=fson[i][now];
    					if(!y){continue;}
    					if(siz[y]-query(1,seg[y],seg[y]+siz[y]-1)<num){continue;}
    					else if(siz[y]-query(1,seg[y],seg[y]+siz[y]-1)==num){flag=true;now=y;break;}
    					else{now=fson[i][now];}
    				}
    				for(register int i=0;i<edge[now].size();++i){
    					int y=edge[now][i].second;
    					int tep=query(1,seg[y],seg[y]+siz[y]-1);
    					if(siz[y]-tep<num){
    						num-=siz[y]-tep;
    						modify_1(1,seg[y],seg[y]+siz[y]-1,1);
    					}
    					else{teproot=y;break;}	
    				}	
    			}
    			print(now);putchar('
    ');
    			modify_1(1,seg[now],seg[now]+siz[now]-1,1);
    		}
    		else{print(uptoroot(num));putchar('
    ');}
    	
    	}
    	return 0;
    } 
    
  • 相关阅读:
    Qt程序使用Win32 API发送ZPL指令与斑马打印机通信
    Eclipse构建Maven项目
    编码风格 缩进和空白
    Linux下Tomcat重新启动
    linux下tomcat服务的相关命令
    第一天
    Day1NLP_机器翻译
    Day4_attention is all you need 论文阅读下篇
    Day_7tensorflow 实战
    Day5_python学习
  • 原文地址:https://www.cnblogs.com/NuoCarter/p/14448898.html
Copyright © 2020-2023  润新知