zoukankan      html  css  js  c++  java
  • BZOJ3786: 星系探索 Splay+DFS序

    题目大意:给你一个树,支持三种操作,子树加,点到根的路径和,改变某一个点的父亲。

    分析:

    看起来像一个大LCT,但是很显然,LCT做子树加我不太会啊...

    那么,考虑更换一个点的父亲这个操作很有意思,也就是说明,整个树的结构不会有什么大的变化,只是某个节点的父亲变了,那么也就是相当于在DFS序上顺序的变化,那么我们就可以考虑化简它的树结构,从而在序列上解决。

    而对于这道题,DFS序能解决,但需要维护更多信息,而且乘法的次数多了很多次,没试,但是应该过不去。我们可以换一种序列,也就是入栈出栈序,这样就可以完美解决了。

    我们动态的维护四个信息,Splay Tree该节点的子树大小,该节点的子树和,和子树正号数量-符号数量符号,Lazy标记。之后每次PushDown的时候用Lazy*num来更新sum。其他的照常。

    关键是每次查询的时候,因为我们不论怎么改变这个序列,有一点从来没有变,就是对应的树上节点在Splay Tree上的节点标号,那么每次只需要找到前驱后继即可,而找到前驱后继显然最好还是用Query_rank和Query_x分别表示找到对应节点的排名和对应排名的节点编号,非递归,记得在Query_x的时候PushDown就可以了!

    之后Rank1什么的,就不用在意了...毕竟Splay的常数...大家知道就好...

    不过我已经尽力了...最快优化到33s,不知道还有没有其他优化...

    附上代码:

    #include <cstdio>
    #include <algorithm>
    #include <cmath>
    #include <cstring>
    #include <cstdlib>
    #include <queue>
    #include <iostream>
    using namespace std;
    #define N 200005
    #define ll long long
    #define ls ch[rt][0]
    #define rs ch[rt][1]
    #define get(rt) (ch[f[rt]][0]!=rt)
    #define PushUp(rt) num[rt]=num[ch[rt][0]]+num[ch[rt][1]]+flag[rt],sum[rt]=sum[ch[rt][0]]+sum[ch[rt][1]]+val[rt]*flag[rt],siz[rt]=siz[ch[rt][0]]+siz[ch[rt][1]]+1
    char buf[100000],*p1,*p2;
    #define nc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++)
    __attribute__((optimize("-O3")))int rd() {
    	register int x=0;register char ch=nc();
    	while(ch<'0'||ch>'9') ch=nc();
    	while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=nc();
    	return x;
    }
    struct node{int to,next;}e[N];
    int head[N],f[N],num[N],siz[N],cnt,flag[N],n,rot,ch[N][2],tmp,tims,a[N],idx[N],p[N];
    ll sum[N];int add[N],val[N];
    void add1(int x,int y){e[cnt]=(node){y,head[x]},head[x]=cnt++;}
    void dfs(int x)
    {
    	idx[++tims]=x;p[x]=tims;
    	for(int i=head[x];i!=-1;i=e[i].next)dfs(e[i].to);
    	idx[++tims]=x+n;p[x+n]=tims;
    }
    void PushDown(int rt)
    {
    	if(add[rt])
    	{
    		sum[ls]+=(long long)(add[rt])*num[ls],val[ls]+=add[rt],add[ls]+=add[rt];
    		sum[rs]+=(long long)(add[rt])*num[rs],val[rs]+=add[rt],add[rs]+=add[rt];
    		add[rt]=0;
    	}
    }
    void rotate(int rt)
    {
    	int x=f[rt],y=f[x],k=get(rt);
    	if(x!=rot)ch[y][ch[y][0]!=x]=rt;else rot=rt;
    	ch[x][k]=ch[rt][!k];f[ch[x][k]]=x;
    	ch[rt][!k]=x;f[x]=rt;f[rt]=y;
    	PushUp(x);PushUp(rt);
    }
    void Splay(int rt,int y)
    {
    	register int fa;
    	for(;(fa=f[rt])!=y;rotate(rt))
    		if(f[fa]!=y)
    			rotate((get(fa)==get(rt))?fa:rt);
    }
    void build(int fa,int l,int r)
    {
    	if(l>r)return;int m=(l+r)>>1;
    	ch[fa][m>fa]=m;f[m]=fa;siz[m]=1;//printf("%d %d %d
    ",idx[m],m,val[m]);
    	build(m,l,m-1);build(m,m+1,r);PushUp(m);
    }
    int query_k(int rt)
    {
    	int ret=0;
    	while(rt)
    	{
    		// PushDown(rt);
    		// printf("%d %d %d
    ",x,idx[rt],ret);
    		if(rt==rot)ret+=siz[ls]+1;
    		else if(get(rt))ret+=siz[ls]+1;
    		else ret-=siz[rs]+1;
    		rt=f[rt];
    	}
    	return ret;
    }
    int find(int x)
    {
    	register int rt=rot;
    	while(1)
    	{
    		PushDown(rt);
    		if(x<=siz[ls])rt=ls;
    		else
    		{
    			x-=siz[ls]+1;
    			if(!x)return rt;
    			rt=rs;
    		}
    	}
    }
    void cut(int x)
    {
    	int rt=find(query_k(p[x+n])+1);x=find(query_k(p[x])-1);
    	Splay(x,0);Splay(rt,rot);tmp=ls;
    	ls=f[ls]=0;PushUp(rt);PushUp(x);
    }
    void link(int x)
    {
    	int rt=find(query_k(p[x])+1);x=find(query_k(p[x]));
    	Splay(x,0);Splay(rt,rot);
    	// printf("%d %d
    ",x,rt);
    	ls=tmp;f[tmp]=rt;PushUp(rt);PushUp(x);
    }
    void Update(int x,int c)
    {
    	int rt=find(query_k(p[x+n])+1);x=find(query_k(p[x])-1);
    	Splay(x,0);Splay(rt,rot);
    	add[ls]+=c;val[ls]+=c;
    }
    int query(int x)
    {
    	int rt=find(query_k(p[x])+1);x=1;
    	Splay(x,0);Splay(rt,rot);
    	printf("%lld
    ",sum[ls]);
    }char s[2];
    int main()
    {
    	n=rd();memset(head,-1,sizeof(head));
    	for(int i=2,x;i<=n;i++)add1(rd(),i);
    	tims=1;dfs(1);idx[++tims]=tims;idx[1]=0;
    	for(int i=1;i<=n;i++)a[i]=rd();
    	for(int i=2;i<=n*2+1;i++)
    	{
    		int x=idx[i];
    		if(x<=n)val[i]=a[x],flag[i]=1;
    		else val[i]=a[x-n],flag[i]=-1;
    	}
    	build(0,1,2*n+2);rot=n+1;int Q=rd();
    	while(Q--)
    	{
    		char op=nc();
    		while(op!='C'&&op!='Q'&&op!='F')op=nc();
    		int x=rd();
    		if(op=='Q')query(x);
    		else if(op=='C')
    		{
    			cut(x);
    			link(rd());
    		}else Update(x,rd());
    		// print();
    	}
    	return 0;
    }
    

      

  • 相关阅读:
    CentOS下编译搭建LAMP环境
    RabbitMQ消息队列总结
    利用exif.js解决ios手机上传竖拍照片旋转90度问题
    服务器同一个tomcat部署2两个相同的项目
    php curl 转为 x-www-form-urlencoded 方式的坑
    Linux后台运行Java的jar包
    环境隔离与属性替换
    安装与使用adb
    HTTP状态码
    微信小程序官方文档
  • 原文地址:https://www.cnblogs.com/Winniechen/p/9241804.html
Copyright © 2011-2022 走看看