• BZOJ-3065 带插入区间K小值


    这道题为树套树,我自己是替罪羊树套权值线段树。

    此题有三种操作:

    1.询问K值:可通过替罪羊树提取区间+权值线段树合并+二分答案求得

    2.修改:可通过权值线段树的删除+添加操作实现

    3.插入:可通过替罪羊树的插入操作实现

    #include <cstdlib>
    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    #include <cmath>
    #include <cctype>
    #define rep(i, l, r) for(int i=l; i<=r; i++)
    #define clr(x, c) memset(x, c, sizeof(x))
    #define inf 0x7fffffff
    #define ll long long
    #define maxn 80010
    #define maxl 70010
    
    #define l(x) Left[x]
    #define r(x) Right[x]
    #define s(x) Size[x]
    #define k(x) Key[x]
    #define t(x) Tree[x]
    #define ls(x) Size[Left[x]]
    #define rs(x) Size[Right[x]]
    #define a 0.8
    
    using namespace std;
    inline int read()
    {
    	int x=0, f=1; char ch=getchar();
    	while (!isdigit(ch)) {if (ch=='-') f=-1; ch=getchar();}
    	while (isdigit(ch)) x=x*10+ch-'0', ch=getchar();
    	return x*f;
    }
    
    //=========================================================================================
    
    struct node
    {
    	node *l, *r; int sum;
    	node () {sum=0; l=r=NULL;}
    } *blank=new(node);
    void Add(int l, int r, int k, node*&t)
    {
    	if (t==blank) t=new(node), t->l=t->r=blank;
    	t->sum++;
    	if (l==r) return; int mid=(l+r)>>1;
    	if (k<=mid) Add(l, mid, k, t->l); else Add(mid+1, r, k, t->r);
    }
    void Del(int l, int r, int k, node*&t)
    {
    	t->sum--;
    	if (l==r) return; int mid=(l+r)>>1;
    	if (k<=mid) Del(l, mid, k, t->l); else Del(mid+1, r, k, t->r);
    }
    
    //=========================================================================================
    
    int Left[maxn], Right[maxn], Key[maxn], Size[maxn], V=0, roof, dfn[maxn], top;
    node *Tree[maxn];
    void Build(int l, int r, int &t)
    {
    	if (l>r) {t=0; return;}
    	int mid=(l+r)>>1; 
    	t=dfn[mid], t(t)=blank, s(t)=r-l+1;
    	rep(i, l, r) Add(0, maxl, k(dfn[i]), t(t));
    	Build(l, mid-1, l(t)), Build(mid+1, r, r(t));
    }
    node *range[maxn];
    int p[maxn], nr, np;
    void ranging(int l, int r, int t) //BST查找区间
    {
    	if (r<ls(t)) ranging(l, r, l(t));  //全在左边
    	else if (l>ls(t)) ranging(l-ls(t)-1, r-ls(t)-1, r(t)); //全在右边
    	else if (!l && r==s(t)-1) range[++nr]=t(t); //整棵树都是
    	else //分跨两边
    	{
    		p[++np]=k(t);
    		if (l<ls(t)) ranging(l, ls(t)-1, l(t));
    		if (r>ls(t)) ranging(0, r-ls(t)-1, r(t));
    	}
    }
    void getrange(int l, int r){nr=np=0; ranging(l-1, r-1, roof);} 
    void dfs(int t){if (l(t)) dfs(l(t)); dfn[++top]=t; if (r(t)) dfs(r(t));} //DFS序
    void Recycle(node *t)  //回收节点
    {
    	if (!t->sum) return;
    	if (t->l) Recycle(t->l);
    	if (t->r) Recycle(t->r);
    	delete(t);
    }
    void reBuild(int &t)
    {
    	top=0; dfs(t); 
    	rep(i, 1, top) Recycle(t(dfn[i])); 
    	Build(1, top, t);
    }
    
    //=========================================================================================
    
    bool Insert(int r, int k, int h, int &t)
    {
    	if (!t)
    	{
    		t=++V;
    		s(t)=1, k(t)=k, l(t)=r(t)=0, t(t)=blank;
    		Add(0, maxl, k, t(t));
    		return h>log(V)/log(1/a);
    	}
    	bool flag;
    	if (r<=ls(t)) 
    		flag=Insert(r, k, h+1, l(t));
    	else flag=Insert(r-ls(t)-1, k, h+1, r(t));
    	s(t)=ls(t)+rs(t)+1; Add(0, maxl, k, t(t));
    	if (flag && (max(ls(t), rs(t)) > a*s(t))) {reBuild(t); return false;}
    	return flag;
    }
    int Change(int r, int k, int t)
    {
    	if (ls(t)==r)
    	{
    		int v=k(t);
    		Del(0, maxl, k(t), t(t));
    		Add(0, maxl, k(t)=k, t(t));
    		return v;
    	}
    	int v;
    	if (r<ls(t)) v=Change(r, k, l(t));
    	else v=Change(r-ls(t)-1, k, r(t));
    	Del(0, maxl, v, t(t));
    	Add(0, maxl, k, t(t));
    	return v;
    }
    int Query(int l, int r, int rank)
    {
    	rank--;
    	getrange(l, r);
    	int L=0, R=maxl;
    	while (L<R)
    	{
    		int mid=(L+R)>>1, sum=0;
    		rep(i, 1, nr) sum+=range[i]->l->sum;
    		rep(i, 1, np) sum+=(p[i]>=L && p[i]<=mid) ? 1 : 0;
    		if (rank<sum)
    			{rep(i, 1, nr) range[i]=range[i]->l; R=mid;}
    		else
    			{rank-=sum; rep(i, 1, nr) range[i]=range[i]->r; L=mid+1;}
    	}
    	return L;
    }
    
    //=========================================================================================
    
    int n, m, w[maxn], last=0;
    int main()
    {
    	blank->l=blank->r=blank;
    	n=read(); rep(i, 1, n) w[i]=read();
    	l(0)=r(0)=s(0)=0;
    	rep(i, 1, n) dfn[i]=++V, k(V)=w[i];
    	Build(1, n, roof);
    	m=read();
    	while (m--)
    	{
    		char ch=getchar(); while (ch!='Q' && ch!='M' && ch!='I') ch=getchar();
    		if (ch=='Q')
    		{
    			int x=read()^last, y=read()^last, z=read()^last;
    			printf("%d
    ", last=Query(x, y, z));
    		}
    		else if (ch=='I')
    		{
    			int x=read()^last, y=read()^last;
    			Insert(x-1, y, 0, roof);
    		}
    		else
    		{
    			int x=read()^last, y=read()^last;
    			Change(x-1, y, roof);
    		}
    	}
    	return 0;
    }
    

      

  • 相关阅读:
    摘录的WinForm Control 开发3,crystalbutton
    摘录的WinForm Control 开发2,CustomColorCheckBox,CustomColorRadioButton
    摘录的WinForm Control 开发4,控件总结
    linq to sql 简单小结:
    摘录的WinForm Control 开发5,WinForm 开发:FlashGetFormDemos ,类似FlashGet的悬浮窗
    SerialPort 的使用
    摘录的WinForm Control 开发5,WinForm 开发:MultipLanguageDemos ,多国语言开发
    摘录的WinForm Control 开发5,WinForm 开发:UnRegularFormDemos ,不规则窗体
    摘录的WinForm control 开发1..BorderLabel
    jquery上传插件(uploadify)的使用
  • 原文地址:https://www.cnblogs.com/NanoApe/p/4445374.html
Copyright © 2020-2023  润新知