zoj 2112 主席树

2014/11/15


 老规矩,想学主席树的这边走疯狂的橡树(推荐),这里只写点自己敲代码的时候遇到的问题。


这颗树是从昨天晚上8点开始敲的,敲到了现在........

其他部分没问题:

先把数组离散化a[ i ]

建个空树

然后以每个a[ i ]节点为根节点根据前一个节点的树来建树。(每棵树省下一半的树节点)

然后问题来了:

建树状数组的时候,其实只理解到了用根节点来建,而每个根节点代表 a[ i ]这个值变动的状态,同样用树来表示,所以有这个根节点。

(每次变动相当于在原来的s[ i ]为根节点的树基础上在建一棵新树,再更新s[ i ],以保证a[ i ]节点 记录其变化动态的树的正确性)

(反正默认利用树状数组进行单点跟新也适用于 树的跟新就对了!=  =)

我就记住 树状数组跟新树的同时,树的节点的值c[ ]也同时跟新(以这个节点为根节点的子树的 重量变化值,不是之前先算出来的值)

最后计算的时候再得出 sum =  原 sum +改动的值。树状数组学过就会明白的= =。

改动的值也不能只计算一棵树, 因为类似划分树,我们要计算出左子树的改动的值,而在 以s[ i ]为根的树中只记录了a[ i ]的变动状态

而一棵左子树的变化的值取决于 1 - i颗树的变化的值的和(这个很好理解:你要计算数组1 -n 中一共变化了多少,就要去计算相加 其中每个元素各自变化了多少)

而树状数组则优化了这个过程。

敲代码的时候:

根据题目输入了 qs[ i ].l  qs[ i]. r  qs[ i ].k.    区间【l ,  r】 第k 大

但是跟新值的时候我图方便 输入了 qs[ i ].l  qs[ i]. r ,用 qs[ i ].k = -inf 来区别,然后忘记了  qs[ i ].l  qs[ i]. r 代表的值的意义:数组中第 x (qs[ i ].l )个节点的值跟新为 y(qs[ i]. r )

然后就莫名的跪了几次。。

郁闷到死啊啊啊啊啊:

好不容易敲完了,WA!WA!WA!

检查了半天( =  12小时)没发现错误,逼急了....我直接去上面某某的博客扒代码。

但是差不多啊 = = 分块的排除错误的可能性。。

最后:

大概就是计算改动的值的时候.....顺序反了一下....就反了一下.......Orzzzzzzzz

是树状数组没学精还是什么...不懂欸 啊喂 QAQ

(补:大概明白了些,因为后面循环里也有这个更新(我的顺序还是反了= =先 树R 在树 L-1)...就会把一些值覆盖)

 AC:  for(i=l-1,use=ua;i;i-=lowbit(i)) use[i]=ls[use[i]];
    sb=sum(l-1);  
 for(i=r  ,use=ub;i;i-=lowbit(i)) use[i]=ls[use[i]];  
   sa=sum(r); 
WA:  
            for(i=r  ,use=ub;i;i-=lowbit(i)) use[i]=ls[use[i]];  
            sa=sum(r); <pre name="code" class="cpp">for(i=l-1,use=ua;i;i-=lowbit(i)) use[i]=ls[use[i]];
            sb=sum(l-1);

 


  AC:for(i=l-1,use=ua;i;i-=lowbit(i)) use[i]=s[i];  
    sb=sum(l-1);  
    for(i=r  ,use=ub;i;i-=lowbit(i)) use[i]=s[i];  
    sa=sum(r)<span style="font-family:Arial, Helvetica, sans-serif;">;</span>
WA:  <pre style="word-wrap: break-word; white-space: pre-wrap;">   for( i = r,use = ub;i;i-=lowbit(i))use[i]= s[i];
   suma = sum(r);
   for( i = l-1,use = ua;i;i-=lowbit(i))use[i]= s[i];
   sumb = sum(l-1);
 

#include<stdio.h>
#include<string.h>
#include<algorithm>

using namespace std;

const int inf = 0x3f3f3f3f;
const int maxm = 2555555;
const int maxn = 105000; 

int ls[maxm],rs[maxm],c[maxm];
int a[maxn],s[maxn],h[maxn],T[maxn],ua[maxn],ub[maxn],*use;
int n, m, len, tot;

struct node{
	int l, r, k;
}sq[10005];


void init()
{
	sort(h,h+len);
	len = unique(h,h+len) - h;
}

int Hash(int x)
{
	return lower_bound(h,h+len,x) - h;
}

int lowbit(int x)
{
	return x&(-x);
}

int build(int l,int r)
{
	int rt = tot++ , mid;
	c[rt] = 0;
	if(l < r)
	{
		mid=(l+r)>>1;
		ls[rt] = build(l,mid);
		rs[rt] = build(mid+1,r);
	}
	return rt;
}



int sum(int x)
{
	int ret = 0;
	while(x)
	{
		ret += c[ls[use[x]]];
		x-=lowbit(x);
	}
	return ret;
}

int update(int prt,int x ,int d)
{
	int srt = tot++,tp = srt, l = 0, r =len-1, mid;
	c[srt] = c[prt] + d;
	while(l < r)
	{
		mid = (l+r)>>1;
		if(x <= mid)
		{
			rs[srt] = rs[prt],ls[srt] = tot++;
			prt = ls[prt];
			srt = ls[srt];
			r = mid;
		}
		else
		{
			ls[srt] = ls[prt],rs[srt] = tot++;
			prt = rs[prt];
			srt = rs[srt];
		    l = mid+1;
		}
		c[srt] = c[prt] + d;
	}
	return tp;
}

void Update(int x,int p,int d)
{
	while(x <= n)
	{
		s[x] = update(s[x],p,d);
		x += lowbit(x);
	}
}

int que(int l ,int r,int k)
{
   int lrt = T[l-1], srt = T[r], mid,ll = 0, rr = len-1, i, sa, sb;
    for(i=l-1,use=ua;i;i-=lowbit(i)) use[i]=s[i];  
    sb=sum(l-1);  
    for(i=r  ,use=ub;i;i-=lowbit(i)) use[i]=s[i];  
    sa=sum(r);  
   
   while(ll < rr)
   {
   	 mid =(ll+rr)>>1;
   	 int tp =sa-sb +c[ls[srt]] - c[ls[lrt]];
     if(k <= tp)
     {
        rr = mid;
	    lrt = ls[lrt];
     	srt = ls[srt];
            for(i=l-1,use=ua;i;i-=lowbit(i)) use[i]=ls[use[i]];
            sb=sum(l-1);  
            for(i=r  ,use=ub;i;i-=lowbit(i)) use[i]=ls[use[i]];  
            sa=sum(r); 

     }
     else
     {
	     ll = mid+1;
     	 k-=tp;
     	 lrt = rs[lrt];
     	 srt = rs[srt];
   		    for(i=l-1,use=ua;i;i-=lowbit(i)) use[i]=rs[use[i]];  
            sb=sum(l-1);  
            for(i=r  ,use=ub;i;i-=lowbit(i)) use[i]=rs[use[i]];  
            sa=sum(r);  
     	
     }
   
   }
   	return ll;
}

int main()
{
	char ch[5];
	int cas;
	
	while(~scanf("%d",&cas))
	{
		while(cas--)
		{
			scanf("%d%d",&n,&m);
			tot=0;
		    len=0;
		for(int i = 1;i <= n; i++)
		{
			scanf("%d",&a[i]);
			h[len++] = a[i];
		}
		
		for(int i = 0;i < m; i++)
		{
		  scanf("%s",ch);
		  if(ch[0]=='Q')
		  {
  		  	scanf("%d%d%d",&sq[i].l,&sq[i].r,&sq[i].k);
  		   }
  		   else 
  		   {
   		  	scanf("%d%d",&sq[i].l,&sq[i].r);
   		  	sq[i].k = -inf;
   		  	h[len++] = sq[i].r;
   		   }
		}
		
		init();
		for(int i = 1;i <= n; i++)
		s[i] = T[0];
		
		T[0] = build(0,len-1);
		
		for(int i = 1;i <= n; i++)
		{
			T[i] = update(T[i-1],Hash(a[i]),1);
		}
		
		
		
		for(int i = 0;i < m; i++)
		{
			if(sq[i].k == -inf)
			{
			  	Update(sq[i].l,Hash(a[sq[i].l]),-1);
			  	Update(sq[i].l,Hash(sq[i].r),1);
			    a[sq[i].l] = sq[i].r;
			}
			else
			{
				printf("%d\n",h[que(sq[i].l,sq[i].r,sq[i].k)]);
			}
		}
		}
	}
	return 0;
}







  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值