zoukankan      html  css  js  c++  java
  • 【UOJ295】【ZJOI2017】线段树 倍增

    题目大意

      http://uoj.ac/problem/295

    题解

      考虑像 zkw 线段树一样,从 ([l-1,l-1],[r+1,r+1]) 这两个区间开始往上跳,直到两个指针碰到一起为止。

      先求出每个点往上跳直到这个点是父亲的左儿子的点,再求出每个点往上跳直到这个点是父亲的右儿子的点。

      这样就可以快速求出要求的区间的信息了。

      然后对这几个东西搞个倍增或树剖就可以快速定位到一个点了。

      把 (dist(x,y)) 拆成 (dist(x,y)=d_x+d_y-2d_{lca(x,y)}),对三部分分开求。

      前两部分很好求,第三部分就分类讨论一下,在链上跳就好了。

      时间复杂度:(O(n+mlog n))

    代码

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cstdlib>
    #include<ctime>
    #include<utility>
    #include<functional>
    #include<cmath>
    #include<vector>
    //using namespace std;
    using std::min;
    using std::max;
    using std::swap;
    using std::sort;
    using std::reverse;
    using std::random_shuffle;
    using std::lower_bound;
    using std::upper_bound;
    using std::unique;
    using std::vector;
    typedef long long ll;
    typedef unsigned long long ull;
    typedef double db;
    typedef std::pair<int,int> pii;
    typedef std::pair<ll,ll> pll;
    void open(const char *s){
    #ifndef ONLINE_JUDGE
    	char str[100];sprintf(str,"%s.in",s);freopen(str,"r",stdin);sprintf(str,"%s.out",s);freopen(str,"w",stdout);
    #endif
    }
    void put(int x){if(!x){putchar('0');return;}static int c[20];int t=0;while(x){c[++t]=x%10;x/=10;}while(t)putchar(c[t--]+'0');}
    int upmin(int &a,int b){if(b<a){a=b;return 1;}return 0;}
    int upmax(int &a,int b){if(b>a){a=b;return 1;}return 0;}
    const int N=200010;
    int ls[2*N],rs[2*N];
    int cnt;
    int rt;
    int pos;
    int c[2*N],e[2*N];
    int a[2*N];
    int st[2*N];
    int ed[2*N];
    int ti;
    int d[2*N];
    int f[2*N];
    int lf[2*N];
    int rf[2*N];
    int lv[2*N];
    ll ld[2*N];
    int rv[2*N];
    ll rd[2*N];
    int f1[2*N][20];
    int f2[2*N][20];
    int f3[2*N][20];
    void build(int &p,int l,int r,int fa,int dep)
    {
    	p=++cnt;
    	st[p]=++ti;
    	d[p]=dep;
    	f[p]=fa;
    	if(p==ls[f[p]])
    	{
    		lf[p]=f[p];
    		rf[p]=rf[f[p]];
    	}
    	else
    	{
    		lf[p]=lf[f[p]];
    		rf[p]=f[p];
    	}
    	
    	
    	if(l==r)
    	{
    		lv[p]=lv[lf[p]];
    		ld[p]=ld[lf[p]];
    		rv[p]=rv[rf[p]];
    		rd[p]=rd[rf[p]];
    		a[l]=p;
    		ed[p]=ti;
    		return;
    	}
    	
    	lv[p]=1;
    	ld[p]=dep+1;
    	rv[p]=1;
    	rd[p]=dep+1;
    	
    	lv[p]+=lv[lf[p]];
    	ld[p]+=ld[lf[p]];
    	rv[p]+=rv[rf[p]];
    	rd[p]+=rd[rf[p]];
    	
    	e[p]=c[++pos];
    	build(ls[p],l,e[p],p,dep+1);
    	build(rs[p],e[p]+1,r,p,dep+1);
    	ed[p]=ti;
    }
    int n,m;
    void init()
    {
    	for(int i=1;i<=cnt;i++)
    	{
    		f1[i][0]=f[i];
    		for(int j=1;j<=19;j++)
    			f1[i][j]=f1[f1[i][j-1]][j-1];
    		f2[i][0]=lf[i];
    		for(int j=1;j<=19;j++)
    			f2[i][j]=f2[f2[i][j-1]][j-1];
    		f3[i][0]=rf[i];
    		for(int j=1;j<=19;j++)
    			f3[i][j]=f3[f3[i][j-1]][j-1];
    	}
    }
    int getlca(int x,int y)
    {
    	if(d[x]<d[y])
    		swap(x,y);
    	for(int i=19;i>=0;i--)
    		if(d[f1[x][i]]>=d[y])
    			x=f1[x][i];
    	if(x==y)
    		return x;
    	for(int i=19;i>=0;i--)
    		if(f1[x][i]!=f1[y][i])
    		{
    			x=f1[x][i];
    			y=f1[y][i];
    		}
    	return f1[x][0];
    	while(x!=y)
    		if(d[x]>d[y])
    			x=f[x];
    		else
    			y=f[y];
    	return x;
    }
    int is_ancestor(int x,int y)
    {
    	return st[x]<=st[y]&&ed[x]>=ed[y];
    }
    ll query_l_chain(int x,int u)
    {
    	if(!ls[x])
    		x=lf[x];
    	ll res=(ll)lv[x]*d[u]+ld[x];
    	int lca=getlca(x,u);
    	for(int i=19;i>=0;i--)
    		if(d[f2[x][i]]>d[lca])
    		{
    			res-=d[lca]<<(i+1);
    			x=f2[x][i];
    		}
    //	res-=2*d[lca];
    //	x-=f2[x][0];
    	while(d[x]>d[lca])
    	{
    		res-=2*d[lca];
    		x=lf[x];
    	}
    	if(!x)
    		return res;
    	if(is_ancestor(rs[x],u))
    		res-=2*(d[lca]+1);
    	else
    		res-=2*d[x];
    	res-=2*(ld[lf[x]]-lv[lf[x]]);
    	return res;
    }
    ll query_r_chain(int x,int u)
    {
    	if(!rs[x])
    		x=rf[x];
    	ll res=(ll)rv[x]*d[u]+rd[x];
    	int lca=getlca(x,u);
    	for(int i=19;i>=0;i--)
    		if(d[f3[x][i]]>d[lca])
    		{
    			res-=d[lca]<<(i+1);
    			x=f3[x][i];
    		}
    //	res-=2*d[lca];
    //	x-=f3[x][0];
    	while(d[x]>d[lca])
    	{
    		res-=2*d[lca];
    		x=rf[x];
    	}
    	if(!x)
    		return res;
    	if(is_ancestor(ls[x],u))
    		res-=2*(d[lca]+1);
    	else
    		res-=2*d[x];
    	res-=2*(rd[rf[x]]-rv[rf[x]]);
    	return res;
    }
    ll query(int u,int l,int r)
    {
    	l--;
    	r++;
    	int x=a[l];
    	int y=a[r];
    	int lca=getlca(x,y);
    	ll s1=query_l_chain(x,u);
    	ll s2=query_l_chain(lca,u);
    	ll s3=query_r_chain(y,u);
    	ll s4=query_r_chain(lca,u);
    	return s1-s2+s3-s4;
    }
    int main()
    {
    	open("loj2570");
    	scanf("%d",&n);
    	c[1]=0;
    	c[2]=n;
    	for(int i=3;i<=n+1;i++)
    		scanf("%d",&c[i]);
    	build(rt,0,n+1,0,1);
    	init();
    	scanf("%d",&m);
    	int u,l,r;
    	for(int i=1;i<=m;i++)
    	{
    		scanf("%d%d%d",&u,&l,&r);
    		u+=3;
    		printf("%lld
    ",query(u,l,r));
    	}
    	return 0;
    }
    
  • 相关阅读:
    QGraphicsItem鼠标旋转控制研究
    QT场景视图父子关系图元打印研究
    QT绘制B样条曲线
    [转]localhost、127.0.0.1和0.0.0.0和本机IP的区别
    [转]C++ 堆栈溢出的原因以及可行的解决方法
    C++运算符重载学习总结
    关于C++中使用++it还是it++的问题
    [转]QT中的D指针与Q指针
    Python图像处理库:Pillow 初级教程
    STEP-MXO2开发板 [STEP FPGA开源社区]
  • 原文地址:https://www.cnblogs.com/ywwyww/p/9609303.html
Copyright © 2011-2022 走看看