bzoj 3600: 沒有人的算術 (替罪羊樹)


爲什麼我沒有copy題面呢?看到題面你就懂了....hh


題意:

定義一個二元組(二元組的兩個元素可以是二元組)

如(x,y),其中x可以是(a,(b,c))之類的

定義二元組的比較方式:先比較左邊,左邊相同再比較右邊。

遞歸比較可以用隨便哪顆平衡樹維護,70分


考慮對於每個 二元組,對他定義一個實數的映射來表示它的大小,想象我們在將它插入平衡樹時,一路比較,按照比較結果判斷是插入左子樹還是右子樹,那實際上它最終的位置就是他的映射,70分做法即爲如此,缺陷在於比較是log的,可是,我們既然已經知道他所在最終位置(映射出的實數),且映射的大小關係等價於它本身的大小關係,那爲何不用映射出的實數去構造新的二元組呢?這樣比較就變成O(1)的了。

可是,映射顯然只是一種相對的位置關係,常用的平衡樹均有旋轉操作,那就意味着映射大小改變,將不斷的重新計算映射,得不償失。可是,非旋轉treap和替罪羊樹並無旋轉操作啊!


代碼:

#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<climits>
#include<queue>
#include<stack>
#include<map>
#include<set>
#define N 500020
using namespace std;
inline int read()
{
    int x=0,f=1;char ch;
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
int n,m;
double a[N];
int ts[N],tot;
int R,rt,pos[N],mx[N];
struct data
{
    int l,r;
    friend bool operator < (data x,data y)
    {
	if(a[x.l]<a[y.l])return 1;
	if(a[x.l]==a[y.l]&&a[x.r]<a[y.r])return 1;
	return 0;
    }	
    friend bool operator == (data x,data y)
    {
	if(a[x.l]!=a[y.l]||a[x.r]!=a[y.r])return 0;
	return 1;
    }
};
struct sctree
{
    int cnt,size[N],ls[N],rs[N];
    data v[N];
    void dfs(int k)
    {
		if(!k)return ;
		dfs(ls[k]);
		ts[++tot]=k;
		dfs(rs[k]);
    }
    void build(int &u,int l,int r,double lv,double rv)
    {
		if(l>r){u=0;return;}
		double mv=(lv+rv)/2.0;
		int mid=(l+r)>>1;
		u=ts[mid];a[u]=mv;
		build(ls[u],l,mid-1,lv,mv);
		build(rs[u],mid+1,r,mv,rv);
		size[u]=size[ls[u]]+size[rs[u]]+1;
    }
    void rebuild(int &u,double lv,double rv)
    {
		tot=0;dfs(u);
		build(u,1,tot,lv,rv);
    }
    int insert(int &u,double lv,double rv,data val)
    {
		double mv=(lv+rv)/2.0;
		if(!u)
		{
		    u=++cnt;v[u]=val;
		    a[u]=mv;size[u]=1;
		    return u;
		}
		int p;
		if(val==v[u])return u;
		else
		{
		    size[u]++;
		    if(val<v[u])p=insert(ls[u],lv,mv,val);
		    else p=insert(rs[u],mv,rv,val);
		}
		if(size[u]*0.75>max(size[ls[u]],size[rs[u]]))
		{
		    if(R)
		    {
				if(ls[u]==R)rebuild(ls[u],lv,mv);
				else rebuild(rs[u],mv,rv);
				R=0;
		    }
		}
		else R=u;
		return p;
    }
}sc;
void add(int u,int l,int r,int v)
{
    if(l==r){mx[u]=v;return;}
    int mid=(l+r)>>1;
    if(v<=mid)add(u<<1,l,mid,v);
    else add(u<<1|1,mid+1,r,v);
    int x=mx[u<<1],y=mx[u<<1|1];
    if(a[pos[x]]<a[pos[y]])mx[u]=y;
    else mx[u]=x;
}

int query(int u,int l,int r,int x,int y)
{
    if(x==l&&y==r)return mx[u];
    int mid=(l+r)>>1;int ret=0;
    if(y<=mid)return query(u<<1,l,mid,x,y);
    else if(x>mid)return query(u<<1|1,mid+1,r,x,y);
    else
    {
		int s=query(u<<1,l,mid,x,mid);
		int t=query(u<<1|1,mid+1,r,mid+1,y);
		if(a[pos[s]]>a[pos[ret]])ret=s;
		if(a[pos[t]]>a[pos[ret]])ret=t;
    }return ret;
}
int main()
{
    n=read(),m=read();char ch[10];
    a[0]=-1;sc.insert(rt,0,1,(data){0,0});
    for(int i=1;i<=n;i++)pos[i]=1;
    for(int i=1;i<=n;i++)add(1,1,n,i);
    for(int i=1;i<=m;i++)
    {
		scanf("%s",ch);
		int l=read(),r=read();
		if(ch[0]=='C')
		{
	    	int k=read();
	    	pos[k]=sc.insert(rt,0,1,(data){pos[l],pos[r]});
	    	if(R)sc.rebuild(rt,0,1);R=0;
	    	add(1,1,n,k);
		}
		else printf("%d\n",query(1,1,n,l,r));
    }
}



























發佈了143 篇原創文章 · 獲贊 22 · 訪問量 9萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章