zoukankan      html  css  js  c++  java
  • 【BZOJ4867】【洛谷P5210】【ZJOI2017】—线段树(括号序列+树链剖分)

    BZOJ

    洛谷

    LOJ


    丢人O(nlog2n)O(nlog^2n)大常数跑不过BZOJBZOJ老爷机

    考虑如果当前询问区间为[l,r][l,r]
    我们从l1l-1r+1r+1的叶子节点往上走到lca(l1,r+1)lca(l-1,r+1)
    l1l-1往上所有右儿子记下来,r+1r+1所有左儿子记下来

    那得到的区间就是要求的定位区间
    但是每次定位显然也是不行的
    考虑如何维护这样一堆儿子

    以右儿子为例
    考虑用类似括号序列的方法
    dfsdfs到某个点的时候,把(rc,1)(rc,1)加到序列里
    dfsdfs左儿子,再次回来的时候把(rc,1)(rc,-1)加到序列里
    dfsdfs右儿子

    可以发现这样l1,lcal-1,lca之间的路径就变成了序列上的一段区间
    现在问题就变成了给定一个序列上的区间
    询问区间所有点到某一个指定点的距离

    dis(u,v)=dep(u)+dep(v)2dep(lca)dis(u,v)=dep(u)+dep(v)-2*dep(lca)
    两个depdep很好维护
    我们考虑如何维护dep(lca)sum dep(lca)
    就是LcaLca这道题

    复杂度O(nlog2n)O(nlog^2n)大常数被O(nlogn)O(nlogn)踩爆了

    #include<bits/stdc++.h>
    using namespace std;
    const int RLEN=1<<20|1;
    inline char gc(){
    	static char ibuf[RLEN],*ib,*ob;
    	(ob==ib)&&(ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
    	return (ib==ob)?EOF:*ib++;
    }
    inline int read(){
    	char ch=gc();
    	int res=0,f=1;
    	while(!isdigit(ch))f^=ch=='-',ch=gc();
    	while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=gc();
    	return f?res:-res;
    }
    #define ll long long
    #define pii pair<int,int>
    #define fi first
    #define se second
    #define pb push_back
    #define mp make_pair
    const int N=800005;
    struct ask{
    	int l,coef,id;
    };
    vector<ask> q[2][N<<1];
    vector<int> e[N];
    int pos[2][N],dfn[2],in[2][N],val[2][N],*ps,*vl;
    int dn;
    int son[N][2],idx[N],rt,qry[N];
    int n,m,tot;
    ll ans[N];
    int build(int l,int r){
    	int u=++tot;
    	if(l==r){idx[l]=u;return u;}
    	int mid=read();
    	son[u][0]=build(l,mid);
    	son[u][1]=build(mid+1,r);
    	e[u].pb(son[u][0]),e[u].pb(son[u][1]);
    	return u;
    }
    void dfs1(int u){
    	if(son[u][1])
    		ps[++dfn[0]]=son[u][1],vl[dfn[0]]=1;
    	in[0][u]=dfn[0];
    	if(son[u][0])dfs1(son[u][0]);
    	if(son[u][1])
    		ps[++dfn[0]]=son[u][1],vl[dfn[0]]=-1,dfs1(son[u][1]);
    }
    void dfs2(int u){
    	if(son[u][0])
    		ps[++dfn[1]]=son[u][0],vl[dfn[1]]=1;
    	in[1][u]=dfn[1];
    	if(son[u][1])dfs2(son[u][1]);
    	if(son[u][0])
    		ps[++dfn[1]]=son[u][0],vl[dfn[1]]=-1,dfs2(son[u][0]);
    }
    namespace Tr{
    	ll tr[N<<2];int tag[N<<2];
    	#define lc (u<<1)
    	#define rc ((u<<1)|1)
    	#define mid ((l+r)>>1)
    	inline void pushup(int u){
    		tr[u]=tr[lc]+tr[rc];
    	}
    	inline void pushdown(int u,int l,int r){
    		if(!tag[u])return ;
    		tag[lc]+=tag[u],tag[rc]+=tag[u];
    		tr[lc]+=1ll*(mid-l+1)*tag[u],tr[rc]+=1ll*(r-mid)*tag[u];
    		tag[u]=0;
    	}
    	void update(int u,int l,int r,int st,int des,int k){
    		if(st<=l&&r<=des){tag[u]+=k,tr[u]+=1ll*(r-l+1)*k;return;}
    		pushdown(u,l,r);
    		if(st<=mid)update(lc,l,mid,st,des,k);
    		if(mid<des)update(rc,mid+1,r,st,des,k);
    		pushup(u);
    	}
    	ll query(int u,int l,int r,int st,int des){
    		if(st<=l&&r<=des){return tr[u];}
    		pushdown(u,l,r);ll res=0;
    		if(st<=mid)res+=query(lc,l,mid,st,des);
    		if(mid<des)res+=query(rc,mid+1,r,st,des);
    		pushup(u);return res;
    	}
    	inline void clear(){
    		memset(tr,0,sizeof(tr)),memset(tag,0,sizeof(tag));
    	}
    	int In[N],dfn,siz[N],hson[N],top[N],dep[N],fa[N];
    	void dfs1(int u){
    		siz[u]=1;
    		for(auto &v:e[u]){
    			fa[v]=u,dep[v]=dep[u]+1;
    			dfs1(v),siz[u]+=siz[v];
    			if(siz[v]>siz[hson[u]])hson[u]=v;
    		}
    	}
    	void dfs2(int u,int tp){
    		In[u]=++dfn,top[u]=tp;
    		if(hson[u])dfs2(hson[u],tp);
    		for(auto &v:e[u]){
    			if(v==hson[u])continue;
    			dfs2(v,v);
    		}
    	}
    	inline void init(){
    		dep[rt]=1,dfs1(rt),dfs2(rt,rt);
    	}
    	inline void pathupdate(int u,int v,int k){
    		while(top[u]!=top[v]){
    			if(dep[top[u]]<dep[top[v]])swap(u,v);
    			update(1,1,dfn,In[top[u]],In[u],k);
    			u=fa[top[u]];
    		}
    		if(dep[u]<dep[v])swap(u,v);
    		update(1,1,dfn,In[v],In[u],k);
    	}
    	inline ll pathquery(int u,int v){
    		ll res=0;
    		while(top[u]!=top[v]){
    			if(dep[top[u]]<dep[top[v]])swap(u,v);
    			res+=query(1,1,dfn,In[top[u]],In[u]);
    			u=fa[top[u]];
    		}
    		if(dep[u]<dep[v])swap(u,v);
    		res+=query(1,1,dfn,In[v],In[u]);
    		return res;
    	}
    	inline int Lca(int u,int v){
    		while(top[u]!=top[v]){
    			if(dep[top[u]]<dep[top[v]])swap(u,v);
    			u=fa[top[u]];
    		}
    		return dep[u]<dep[v]?u:v;
    	}
    }
    inline void query(int u,int l,int r,int id){
    	l=idx[l-1],r=idx[r+1];
    	int lca=Tr::Lca(l,r);
    	q[0][in[0][l]].pb(ask{u,1,id});
    	q[0][in[0][lca]].pb(ask{u,-1,id});
    	q[1][in[1][r]].pb(ask{u,1,id});
    	q[1][in[1][lca]].pb(ask{u,-1,id});
    }
    inline void calc(int ID,int *pos,int dfn,int *val,int *in){
    	ll sum0=0,sum1=0;
    	for(int i=1;i<=dfn;i++){
    		sum0+=val[i],sum1+=Tr::dep[pos[i]]*val[i];
    		Tr::pathupdate(rt,pos[i],val[i]);
    		for(auto &x:q[ID][i]){
    			ll res=sum0*Tr::dep[x.l];
    			res+=sum1,res-=2ll*Tr::pathquery(x.l,rt);
    			ans[x.id]+=res*x.coef;
    		}
    	}
    	Tr::clear();
    }
    signed main(){
    	n=read();
    	build(1,n);
    	idx[0]=++tot,idx[n+1]=++tot;
    	rt=++tot;son[rt][0]=idx[0],son[rt][1]=++tot;
    	e[rt].pb(idx[0]),e[rt].pb(tot);
    	son[tot][0]=1,son[tot][1]=idx[n+1];
    	e[tot].pb(1),e[tot].pb(idx[n+1]);
    	Tr::init();
    	ps=pos[0],vl=val[0];
    	dfs1(rt),ps=pos[1],vl=val[1];
    	dfs2(rt),m=read();
    	for(int i=1;i<=m;i++){
    		int u=read(),l=read(),r=read();
    		query(u,l,r,i);
    	}
    	calc(0,pos[0],dfn[0],val[0],in[0]),calc(1,pos[1],dfn[1],val[1],in[1]);
    	for(int i=1;i<=m;i++)cout<<ans[i]<<'
    ';exit(0);
    }
    
  • 相关阅读:
    微软一站式示例代码浏览器 v5.1 更新
    Developers’ Musthave: the new Microsoft AllInOne Code Framework Sample Browser and 3500+ samples
    栈溢出攻击 [转]
    深入浅出Java的访问者模式 [转]
    优先级反转 [转]
    latex 引用section [转]
    linux内存管理浅析 [转]
    静态,动态,强类型,弱类型 [转]
    linux硬链接与软链接 [转]
    GCC __attribute__ 详解 [转]
  • 原文地址:https://www.cnblogs.com/stargazer-cyk/p/11145537.html
Copyright © 2011-2022 走看看