zoukankan      html  css  js  c++  java
  • 4.18 省选模拟赛 消息传递 树剖 倍增 线段树维护等比数列

    avatar
    avatar

    把树剖和倍增 线段树的联系诠释的很完美。

    题目意思:自行理解。

    做法:设两个点x,y x能挡住y 且在k点处 那么至少的得到一个式子 tx+dx-dk<tx+dy-dk

    从这个式子中可以发现 按tx+dx这个排序 前面的可以有可能挡住后面的 同时相等时题目中的要求小的编号优先。

    我们考虑一个点挡住当前的这个点的去路 设sx表示x这个点当前不能通过的时间 那么当 dy-dx+ty>=sx时可以通过反之不行。且x时y到根的路径上的点。

    将等式变形 容易发现 dy+ty>=sx+dx.

    每次其实就是链上查询一点 然后链上赋值操作。

    考虑前者 树剖向上跳 然后发现当前到top点之间不能直接跳之后换倍增跳。(树剖与倍增的一个小trick。

    考虑后者 赋值操作可以发现时一个等差数列 但是还不能直接赋值 因为还有基础数值深度。

    此时 赋值的时候 可以发现可以直接赋上深度就可以解决这个问题了。那么等差数列的公差就就变成了2.

    线段树+树剖维护等差数列的修改即可。

    真的巧妙。

    const int MAXN=200010;
    int n,Q,len,rt,cnt;
    int f[MAXN][20],Log[MAXN],son[MAXN],id[MAXN],sz[MAXN],top[MAXN];
    int lin[MAXN],ver[MAXN],nex[MAXN],pos[MAXN],d[MAXN],ans[MAXN];
    struct wy{int x,ti,id;}t[MAXN];
    struct jl{int l,r,sum,tag,d;}s[MAXN<<2];
    inline int cmp(wy a,wy b){return a.ti+d[a.x]==b.ti+d[b.x]?a.x<b.x:a.ti+d[a.x]<b.ti+d[b.x];}
    inline void add(int x,int y)
    {
    	ver[++len]=y;
    	nex[len]=lin[x];
    	lin[x]=len;
    }
    inline void dfs(int x,int fa)
    {
    	sz[x]=1;f[x][0]=fa;
    	d[x]=d[fa]+1;
    	rep(1,Log[d[x]],i)f[x][i]=f[f[x][i-1]][i-1];
    	go(x)
    	{
    		dfs(tn,x);
    		sz[x]+=sz[tn];
    		if(sz[tn]>sz[son[x]]||!son[x])son[x]=tn;
    	}
    }
    inline void dp(int x,int fa)
    {
    	id[x]=++cnt;pos[cnt]=x;top[x]=fa;
    	if(!son[x])return;
    	dp(son[x],fa);
    	go(x)if(tn!=son[x])dp(tn,tn);
    }
    inline void pushup(int p){sum(p)=max(sum(zz),sum(yy));}
    inline void build(int p,int l,int r)
    {
    	l(p)=l;r(p)=r;
    	if(l==r)return;
    	int mid=(l+r)>>1;
    	build(zz,l,mid);
    	build(yy,mid+1,r);
    }
    inline void push(int p,int x,int w)
    {
    	d(p)=w;tag(p)=x;
    	sum(p)=x+(r(p)-l(p))*w;
    }
    inline void pushdown(int p)
    {
    	int mid=(l(p)+r(p))>>1;
    	push(zz,tag(p),d(p));
    	push(yy,tag(p)+(mid-l(p)+1)*d(p),d(p));
    	d(p)=tag(p)=0;
    }
    inline void change(int p,int l,int r,int x,int w)
    {
    	if(l==l(p)&&r==r(p)){push(p,x,w);return;}
    	int mid=(l(p)+r(p))>>1;
    	if(tag(p)||d(p))pushdown(p);
    	if(r<=mid)change(zz,l,r,x,w);
    	else 
    	{
    		if(l>mid)change(yy,l,r,x,w);
    		else change(zz,l,mid,x,w),change(yy,mid+1,r,x+w*(mid-l+1),w);
    	}
    	pushup(p);
    }
    inline int ask(int p,int l,int r)
    {
    	if(l<=l(p)&&r>=r(p))return sum(p);
    	int mid=(l(p)+r(p))>>1,cnt=0;
    	if(d(p)||tag(p))pushdown(p);
    	if(l<=mid)cnt=max(cnt,ask(zz,l,r));
    	if(r>mid)cnt=max(cnt,ask(yy,l,r));
    	return cnt;
    }
    int main()
    {
    	freopen("1.in","r",stdin);
    	//freopen("1.out","w",stdout);
    	get(n);get(Q);
    	rep(1,n,i)add(read(),i),Log[(i+1)]=Log[(i+1)>>1]+1;
    	dfs(0,0);dp(0,0);
    	build(1,1,cnt);change(1,1,1,INF,0);
    	rep(1,Q,i){int get(x);t[i]=(wy){x,read(),i};}
    	sort(t+1,t+1+Q,cmp);
    	rep(1,Q,i)
    	{
    		int x=t[i].x;
    		while(ask(1,id[top[x]],id[x])<=t[i].ti+d[t[i].x])x=f[top[x]][0];
    		fep(Log[d[x]],0,j)
    		{
    			if(d[f[x][j]]<d[top[x]])continue;
    			if(ask(1,id[f[x][j]],id[x])<=t[i].ti+d[t[i].x])x=f[x][j];
    		}
    		int cc;if(ask(1,id[x],id[x])<=t[i].ti+d[t[i].x])cc=f[x][0];else cc=x;
    		ans[t[i].id]=(d[t[i].x]-d[cc])*2+t[i].ti;
    		x=t[i].x;
    		//cout<<cc<<endl;
    		while(top[cc]!=top[x])
    		{
    			change(1,id[top[x]],id[x],t[i].ti+d[t[i].x]-d[cc]+d[top[x]]-d[cc]+d[top[x]],2);
    			//cout<<t[i].ti+d[t[i].x]-d[cc]+d[top[x]]-d[cc]+d[top[x]]<<endl;
    			x=f[top[x]][0];
    		}
    		if(x!=cc)change(1,id[cc]+1,id[x],t[i].ti+d[t[i].x]+2,2);
    		//cout<<t[i].ti+d[t[i].x]+2<<endl;
    	}
    	rep(1,Q,i)printf("%d ",ans[i]);
    	return 0;
    }
    

    坑点 Log数组要到n+1 排序的时候别打错。

  • 相关阅读:
    element-ui 多张图上传
    js json生取key,value 值
    iview DatePicker 回显验证报错
    iview的Select控制value为数字类型时表单验证无法通过
    iview 自定义树形
    tree 树形递归修改 key
    根据月份选择 生成这个月的每一天
    微信小程序超出隐藏省略号和自动换行
    uni-app picker select 取想要的值
    element-ui 表格fixed 样式修改
  • 原文地址:https://www.cnblogs.com/chdy/p/12748555.html
Copyright © 2011-2022 走看看