平衡树练习——被虐记~~

最近做的一份jsoi2011冬令营的卷子,瞬间被虐暴了。。。。。

其中以两道平衡树最为奇葩。

蒟蒻今天终于写完了两道平衡树——调了好长好长时间睡觉,高级数据结构能力太渣了大哭


--------------------------------------------华丽的分割线--------------------------------------------


(最近搞了个强大的截图工具)题面就不概述了,直接放图吧


一眼看上去就是splay吧。

读入后从最后一个询问倒序处理,删除变成添加,用启发式合并,修改变成复原,询问直接处理吧微笑

然后蒟蒻令人捉急的代码能力就开始显现出来了,一调一下午。。。。。

主要是忘记了splay删除怎么写了难过。。。原来写了个好龊好龊的,现在好不容易想起来,这里补一个备忘

void del(int x,int tr){
  Splay(x,0,tr);
  int pr=son[x][0], nx=son[x][1];
  if (pr==0)
    { root[tr]=nx; fa[nx]=0; return; }
  if (nx==0)
    { root[tr]=pr; fa[pr]=0; return; }
  while (son[pr][1]) pr=son[pr][1];
  while (son[nx][0]) nx=son[nx][0];
  Splay(pr,0,tr); Splay(nx,pr,tr);
  son[nx][0]=0; Splay(nx,0,tr);
}

看着这凝结着我半天的代码我情何以堪啊。。。。


#include <vector>
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;
const int Maxn=30005, Maxm=100005, Maxq=500005;
int son[Maxn][2],fa[Maxn],size[Maxn],root[Maxn],ft[Maxn];
int n,m,i,q,m1,m2,cnt,ans,tot,num[Maxq],data[Maxn];
bool v[Maxm];
char s[Maxq];
vector <int> e[Maxn];
struct EDGE
{
  int x,y;
  bool operator <(const EDGE &a)const
  { return (x<a.x) || (x==a.x && y<a.y); }
  bool operator ==(const EDGE &a)const
  { return (x==a.x && y==a.y); }
} edge[Maxm], g[Maxq], tmp;

void rotate(int x,int f,int K){
  if (fa[f]!=0){
  	if (son[fa[f]][0]==f)
  	  son[fa[f]][0]=x;
  	else son[fa[f]][1]=x;
  }
  fa[x]=fa[f];
  
  if (son[x][K^1]) fa[son[x][K^1]]=f;
  son[f][K]=son[x][K^1];
  
  son[x][K^1]=f; fa[f]=x;
  size[f]=size[son[f][0]] +size[son[f][1]]+ 1;
}

void Splay(int x,int y,int tr){
  int f,gf;
  while (fa[x]!=y){
  	f=fa[x]; gf=fa[f];
  	if (gf==y){
  	  if (son[f][0]==x) rotate(x,f,0);
  	  if (son[f][1]==x) rotate(x,f,1);
  	} else
  	{
  	  if (son[f][0]==x && son[gf][0]==f) rotate(f,gf,0), rotate(x,f,0);
  	  if (son[f][1]==x && son[gf][1]==f) rotate(f,gf,1), rotate(x,f,1);
  	  if (son[f][0]==x && son[gf][1]==f) rotate(x,f,0), rotate(x,gf,1);
  	  if (son[f][1]==x && son[gf][0]==f) rotate(x,f,1), rotate(x,gf,0);
  	}
  }
  if (y==0) root[tr]=x;
  size[x]=size[son[x][0]] +size[son[x][1]]+ 1;
}

void del(int x,int tr){
  Splay(x,0,tr);
  int pr=son[x][0], nx=son[x][1];
  if (pr==0)
    { root[tr]=nx; fa[nx]=0; return; }
  if (nx==0)
    { root[tr]=pr; fa[pr]=0; return; }
  while (son[pr][1]) pr=son[pr][1];
  while (son[nx][0]) nx=son[nx][0];
  Splay(pr,0,tr); Splay(nx,pr,tr);
  son[nx][0]=0; Splay(nx,0,tr);
}

void ins(int x,int tr){
  son[x][0]= son[x][1]= fa[x]=0;
  int y=root[tr];
  if (y==0){
  	root[tr]=x;
  	size[x]=1;
  } else
  while (true){
  	if (data[x]>data[y]){
  	  if (son[y][1]) y=son[y][1];
  	    else {son[y][1]=x; fa[x]=y; break;}
  	}else
	{
	  if (son[y][0]) y=son[y][0];
  	    else {son[y][0]=x; fa[x]=y; break;}
    }
  }
  Splay(x,0,tr);
}

int query(int x,int tr){
  int ret=0;
  int y=root[tr];
  while (y){
  	if (data[y]>=x){
	  ret=data[y];
	  y=son[y][0];
    } else y=son[y][1];
  }
  return ret;
}

void get_together(int x,int y){
  ft[x]=y;
  while (e[x].size()){
  	int tmp=e[x].back();
  	e[x].pop_back();
  	e[y].push_back(tmp);
  	
  	son[tmp][0]=son[tmp][1]=0;
  	fa[tmp]=0;
  	ins(tmp,y);
  }
}

int get_ft(int x){
  int xx=x, xxx;
  while (ft[xx]!=xx) xx=ft[xx];
  while (x!=xx) xxx=x, x=ft[x], ft[xxx]=xx;
  return xx;
}

int main(){
  freopen("boring.in","r",stdin);
  freopen("boring.out","w",stdout);
  scanf("%d%d%d",&n,&m,&q);
  for (i=1;i<=n;i++) scanf("%d",&data[i]);
  for (i=1;i<=m;i++){
  	scanf("%d%d\n",&edge[i].x,&edge[i].y);
  	if (edge[i].x>edge[i].y)
  	  swap(edge[i].x,edge[i].y);
  }
  sort(edge+1,edge+m+1);
  for (i=1;i<=q;i++){
  	scanf("%c%d%d\n",&s[i],&g[i].x,&g[i].y);
  	if (s[i]=='U') swap(data[g[i].x],g[i].y);
        tmp=g[i];
  	if (tmp.x>tmp.y) swap(tmp.x,tmp.y);
  	if (s[i]!='E') continue;
  	num[i]=lower_bound(edge+1,edge+m+1,tmp)-edge;
  	if (edge[ num[i] ]==tmp){
      while (edge[ num[i] ]==tmp && v[num[i]]) num[i]++;
      v[num[i]]=1;
    } else num[i]=0;
  }
  for (i=1;i<=n;i++){
  	size[i]=1;
    ft[i]=i; root[i]=i;
    e[i].push_back(i);
  }
  
  for (i=1;i<=m;i++)
  if (v[i]==0){
  	m1=get_ft(edge[i].x);
  	m2=get_ft(edge[i].y);
  	if (m1==m2) continue;
  	if (e[m1].size()<e[m2].size())
  	  get_together(m1,m2);
  	else get_together(m2,m1);
  }
  
  for (i=q;i>0;i--){
  	if (s[i]=='F'){
  	  m1=get_ft(g[i].x);
  	  cnt+=query(g[i].y,m1);
  	  tot++;
  	} else
  	if (s[i]=='U'){
  	  m1=get_ft(g[i].x);
  	  del(g[i].x,m1);
  	  data[g[i].x]=g[i].y;
  	  ins(g[i].x,m1);
  	} else
  	if (s[i]=='E'){
  	  m1=get_ft(g[i].x);
  	  m2=get_ft(g[i].y);
  	  if (num[i]==0) continue;
  	  v[num[i]]=0;
  	  if (m1==m2) continue;
  	  if (e[m1].size()<e[m2].size())
  	    get_together(m1,m2);
  	  else get_together(m2,m1);
  	}
  }

  double ans=(double)cnt/tot;
  printf("%.3lf\n",ans);
  return 0;
}


--------------------------------------------华丽的分割线--------------------------------------------





暴力链表会吧,空间O(10^9)。。。。10分

朴素暴力会吧,时间O(n^2)。。。。30分

用Splay优化朴素暴力,离散化啥的,呵呵呵呵呵。。。。。。

P很好做啊,Splay维护就好了,关键是L咋办,怎么离散化,蛋疼啊。。。。

注意到问么其实对数列只进行了几次插入,也就是说很多子序列都是以公差为一递增的等差数列!

好有用的样子。这样我们只要保证每个连续的字序列至少开头在Splay树上,找到开头加一下就得到答案了!

分析一下插队的特点(a,b)我们只要把a,a+1,b都放到树里就行了微笑


#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;
#define update(x) if (tip[x]!=0) push(x)
const int Maxn=200005;
int fa[Maxn],son[Maxn][2],rk[Maxn],tip[Maxn],a[Maxn],b[Maxn],c[Maxn];
int n,m,N,x,i,ta,tb,root,q[Maxn];
char s[Maxn];

void push(int x){
  int lc=son[x][0], rc=son[x][1];
  if (lc){
    rk[lc]+=tip[x];
    tip[lc]+=tip[x];
  }
  if (rc){
    rk[rc]+=tip[x];
    tip[rc]+=tip[x];
  }
  tip[x]=0;
}

void rotate(int x,int f,int K){
  if (fa[f]){
    if (son[fa[f]][0]==f) son[fa[f]][0]=x;
      else son[fa[f]][1]=x;
  }
  fa[x]=fa[f];

  son[f][K]=son[x][K^1];
  if (son[x][K^1]) fa[son[x][K^1]]=f;

  son[x][K^1]=f; fa[f]=x;
}

void Splay(int x,int y){
  int f, gf;
  while (fa[x]!=y){
    f=fa[x]; gf=fa[f];
    update(gf); update(f); update(x);
    if (gf==y){
      if (son[f][0]==x) rotate(x,f,0);
      if (son[f][1]==x) rotate(x,f,1);
    } else
    {
      if (son[f][0]==x && son[gf][0]==f) rotate(f,gf,0), rotate(x,f,0);
      if (son[f][1]==x && son[gf][1]==f) rotate(f,gf,1), rotate(x,f,1);
      if (son[f][0]==x && son[gf][1]==f) rotate(x,f,0), rotate(x,gf,1);
      if (son[f][1]==x && son[gf][0]==f) rotate(x,f,1), rotate(x,gf,0);
    }
  }
  update(x);
  if (y==0) root=x;
}

int build(int l,int r){
  if (l>r) return 0;
  int mid=(l+r)>>1;
  rk[mid]=c[mid];
  if (l==r) return l;
  son[mid][0]=build(l,mid-1);
  son[mid][1]=build(mid+1,r);
  fa[son[mid][0]]= fa[son[mid][1]]= mid;
  return mid;
}

void del(int x,int K){
  Splay(x,0);
  if (son[x][0]) rk[son[x][0]]+=K, tip[son[x][0]]+=K;
  int pr=son[x][0], nx=son[x][1];
  if (pr==0)
    { root=son[x][1]; fa[root]=0; return; }
  if (nx==0)
    { root=son[x][0]; fa[root]=0; return; }
  while (son[pr][1]){ update(pr); pr=son[pr][1]; }
  while (son[nx][0]){ update(nx); nx=son[nx][0]; }
  Splay(pr,0);  Splay(nx,pr);
  son[nx][0]=0;
}

void ins(int x,int y,int K){
  Splay(y,0); rk[x]=rk[y]-1;
  son[x][0]= son[x][1]= 0;
  while (y){
    update(y);
    if (rk[y]>rk[x]){
      if (son[y][0]==0)
        {fa[ son[y][0]=x ]=y; break;}
      else y=son[y][0];
    } else
    {
      if (son[y][1]==0)
        {fa[ son[y][1]=x ]=y; break;}
      else y=son[y][1];
    }
  }
  Splay(x,0);
  if (son[x][0]) rk[son[x][0]]+=K, tip[son[x][0]]+=K;
}

void work1(int x){
  x=lower_bound(c,c+N+1,x)-c;
  Splay(x,0);
  printf("%d\n",rk[x]);
}

void work2(int x){
  int y=root, z;
  while (y){
    update(y);
    if (rk[y]==x) {printf("%d\n",c[y]);return;}
    if (rk[y]>x) y=son[y][0];
     else z=y, y=son[y][1];
  }
  printf("%d\n", c[z]+(x-rk[z]) );
}

int main(){
  freopen("queue.in","r",stdin);
  freopen("queue.out","w",stdout);
  scanf("%d",&n);
  c[N=1]=1; c[N=2]=1000000000;
  for (i=1;i<=n;i++){
    scanf("%d%d",&a[i],&b[i]);
    c[++N]=a[i]; c[++N]=b[i];
    c[++N]=a[i]+1;
  }
  scanf("%d\n",&m);
  for (i=1;i<=m;i++){
    scanf("%c %d\n",&s[i],&q[i]);
    if (s[i]=='P') c[++N]=q[i];
  }
  sort(c+1,c+N+1);
  N=unique(c+1,c+N+1)-c-1;
  root=build(1,N);
  for (i=1;i<=n;i++){
    a[i]=lower_bound(c+1,c+N+1,a[i])-c;
    b[i]=lower_bound(c+1,c+N+1,b[i])-c;
	del(a[i],1), ins(a[i],b[i],-1);
  }
  for (i=1;i<=m;i++){
    if (s[i]=='P') work1(q[i]);
      else work2(q[i]);
  }
  return 0;
}


--------------------------------------------华丽的分割线--------------------------------------------


有了这次教训,看来数据结构还是要加强,这几天写写树剖和LCT吧生气

bless all~~~~


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 《PDF城市交通网络平衡分析——理论与实践》是一本介绍城市交通网络平衡分析的书籍。本书主要涵盖了理论与实践方面的内容,旨在帮助读者理解城市交通网络的运行原理以及如何利用平衡分析方法进行分析。 首先,本书对城市交通网络的概念和特点进行了详细的介绍。城市交通网络是指由道路、公共交通、步行和自行车等组成的城市交通系统,其中各个元素之间相互关联,共同构成了城市的交通网络。 其次,本书介绍了城市交通网络平衡分析的理论基础。平衡分析是指在特定的交通需求下,交通网络中各个交通模式之间的流量达到一种平衡状态,即供需匹配的状态。通过理论的介绍,读者可以了解到平衡分析的基本原理、假设条件以及求解方法。 接着,本书从实践的角度出发,介绍了城市交通网络平衡分析的应用。通过实例分析,读者可以了解到平衡分析方法在解决城市交通问题上的实际应用,并且可以学习到如何采集交通需求数据、构建交通模型以及如何使用计算机软件进行模拟仿真。 最后,本书还对城市交通网络的未来发展进行了展望。随着城市化进程的不断推进,城市交通网络的规模和复杂度将会继续增加,因此,进一步深入研究交通网络平衡分析的方法和技术将成为未来的研究方向。 总体而言,《PDF城市交通网络平衡分析——理论与实践》通过理论和实践相结合的方式,全面介绍了城市交通网络平衡分析的内容。这本书对于城市交通规划、交通工程师和相关研究人员来说,将是一本十分有价值的参考书。 ### 回答2: PDF城市交通网络平衡分析——理论与实践是一本关于城市交通网络平衡分析的书籍。这本书通过理论与实践相结合的方式,系统地介绍了城市交通网络平衡分析的方法和应用。 首先,这本书从理论层面介绍了城市交通网络。它详细讲解了交通网络的基本概念、结构和特征,以及交通流的形成和演化规律。同时,书中还介绍了交通需求预测、交通网络建模等理论基础,这些理论知识对于后续的分析和应用是非常重要的。 其次,这本书还介绍了城市交通网络平衡分析的实践方法。它系统地介绍了城市交通数据的采集和处理方法,包括交通调查、交通流量测量和交通数据分析等。同时,书中还介绍了交通模型的建立和求解技术,以及模拟仿真和评价方法,这些方法对于更准确地分析和评估城市交通网络的平衡性具有重要意义。 此外,这本书还介绍了城市交通网络平衡分析的应用领域和实践案例。它涵盖了城市交通规划、交通管理和交通优化等方面的应用,以及不同城市的实际案例研究。通过这些案例,读者可以更好地理解理论与实践的结合,以及交通网络平衡分析在解决实际问题中的作用。 综上所述,PDF城市交通网络平衡分析——理论与实践是一本全面介绍城市交通网络平衡分析的书籍。它既讲解了基本的理论知识,又介绍了实践方法和应用案例,对于研究者和从事城市交通规划和管理工作的人员来说,具有很高的参考价值。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值