[BZOJ3626] LCA - 离线 - 树链剖分/动态树/分块

        大雾啊……BZOJ上是10s题到了我校OJ就成了100MS每点

        目测这是要写树剖+BIT的东西……窝LCT卡常数卡了好久都没艹过去,BZOJ都稳稳前两页了……

        好伐还是说题解吧…… 首先我们可以离线将所有回答排序。首先我们用前缀和思想,即Ans[l,r]=Ans[1,r]-Ans[1,l-1]

        然后我们可以发现,我们每次处理的就是对应的z关于1~a这么多点的LCA的深度之和。

        如果我们将一个点t到根节点连的路径上都加上一个权值1的话,显然dep(lca(t,z))就等于z到根路径上的权值和……

        然后就依次插入点然后乱搞搞了…… 不懂可以看黄学长博客TAT。

#include "stdio.h"
#include "stdlib.h"
#include "algorithm"
#define rep(f,a,b) for(f=a;f<=b;f++)

typedef long long ll;
using namespace std;
const int N=50005,M=2000000;
const int MOD=201314,Q=50005;

char buff[M+5],*__pos;
void ReadIn(){
	fread(buff,sizeof(char),M,stdin);
	__pos=buff;
}

inline int read(){
	int x=0; char ch=*__pos;
	while(ch<'0'||ch>'9') ch=*(++__pos);
	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=*(++__pos);}
	return x;
}

struct node{
	int tag,size,sum,val;
	node *fa,*c[2]; node();
	inline void push_up();
	inline void push_down();
} Tnull, *null=&Tnull, v[N];

node:: node(){
	fa=c[0]=c[1]=null;
	tag=size=sum=val=0;
}

inline void node:: push_up(){
	if(c[0]!=null) c[0]->push_down();
	if(c[1]!=null) c[1]->push_down();
	size=c[0]->size+c[1]->size+1;
	sum=c[0]->sum+c[1]->sum+val;
	if(c[0]!=null)c[0]->fa=this;
	if(c[1]!=null)c[1]->fa=this;
}

inline void node:: push_down(){
	if (tag){
		sum+=size*tag; val+=tag;
		if(c[0]!=null)c[0]->tag+=tag;
		if(c[1]!=null)c[1]->tag+=tag;
		tag=0;
	}
}

inline void rotate (node *x){
	node *y=x->fa,*z=y->fa;
	y->push_down(); x->push_down();
	if(z->c[0]==y) z->c[0]=x;
	if(z->c[1]==y) z->c[1]=x;
	int l=y->c[1]==x,r=l^1;
	x->fa=z; y->fa=x; y->c[l]=x->c[r];
	if(x->c[r]!=null)x->c[r]->fa=y;
	x->c[r]=y; y->push_up();
	x->push_up();
}

inline void splay (node *x){
	x->push_down();
	while (x->fa->c[0]==x||x->fa->c[1]==x){
		node *y=x->fa,*z=y->fa;
		if(y->fa->c[0]==y||y->fa->c[1]==y){
			if (z->c[0]==y ^ y->c[0]==x) rotate(x);
			else rotate(y);
		} 
		rotate(x);
	}
}

inline void access (node *x){
	for (node *y=null; x!=null; y=x,x=x->fa)
		splay(x),x->c[1]=y,x->push_up();
}

typedef struct QueryAskData {
	int l,r,z,id;
	inline void init();
} QAD; QAD quest[Q];

inline void QAD:: init(){
	l=read(),r=read(),z=read();
	id=(int)(this- quest);
	l++,r++,z++;
}

typedef struct QuestAskDataSort{
	int tag,x,id,z;
	inline void ins(int _,int __,int ___,int ____);
	inline bool operator <
	(const QuestAskDataSort &a) const;
} QADS; QADS data[2*Q];

inline bool QADS:: operator <(const QADS&a) const{
	return x==a.x?id<a.id:x<a.x;
}

void QADS:: ins(int _,int __,int ___,int ____)
{ tag=_,z=__,id=___,x=____;}

int ans[Q],n,q;

int main(){
	ReadIn(); n=read(),q=read(); int i,t;
	rep(i,1,n)v[i].size=1;
	rep(i,2,n){
		t=read(); ++t;
		v[i].fa=v+t;
	}
	rep(i,1,q){
		quest[i].init(); if(quest[i].l==1) ++ans[i];
		data[2*i-1].ins(-1,quest[i].z,i,quest[i].l-1);
		data[2*i].ins(1,quest[i].z,i,quest[i].r);
	} sort(data+1,data+2*q+1); int j;
	for (i=j=1;j<=n;j++){
		access(v+j); splay(v+j); v[j].tag++;
		while (data[i].x<=j&&i<=2*q){
			access(v+data[i].z); splay(v+data[i].z);
			v[data[i].z].push_down();
			ans[data[i].id]+=v[data[i].z].sum*data[i].tag;
			i++;
		}
	} rep(i,1,q) printf("%d\n",ans[i]%MOD);
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值