可持久化线段树

给定一个序列 求在 li ri 之间的 数值大小在 【a,b】 的数的个数 有多少个 ?

山东省省赛题目。  当时离线直接水过。 

http://acm.upc.edu.cn/problem.php?id=2224

#include <vector>
#include <list>
#include <map>
#include <set>
#include <deque>
#include <stack>
#include <cstring>
#include <bitset>
#include <algorithm>
#include <functional>
#include <numeric>
#include <utility>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <assert.h>
#include <queue>
#define REP(i,n) for(int i=0;i<n;i++)
#define TR(i,x) for(typeof(x.begin()) i=x.begin();i!=x.end();i++)
#define ALLL(x) x.begin(),x.end()
#define SORT(x) sort(ALLL(x))
#define CLEAR(x) memset(x,0,sizeof(x))
#define FILLL(x,c) memset(x,c,sizeof(x))
using namespace std;
const double eps = 1e-9;
#define LL long long 
#define pb push_back
const int maxn = 100010;
int n,m;
int num[maxn];
struct SegNode {
     SegNode *l,*r;
     int sum;
}nodes[maxn*25];
int C;
SegNode *root[maxn];
struct segmentTree{
	 SegNode *null;
	 void init(){
	 	C = 0;
	 	 null = root[0] = &nodes[C];
	 	 C++;
	 	 null->l = null;
	 	 null->r = null;
	 	 null ->sum = 0;
	 }
	 SegNode * update(int pos,int left ,int right ,SegNode *root,int val){
	 	   SegNode  *rt = &nodes[C++];
	 	   rt->l = root->l;
	 	   rt->r = root->r;
	 	   rt->sum = root->sum;
	 	   if(left == right && pos == left ){
	 	   	     rt->sum +=val;
	 	   	     return rt;
	 	   }
	 	  
	 	   int mid = (left +right) >>1;
	 	   if(pos<=mid){
	 	   	    rt->l = update(pos,left ,mid,root->l,val);
	 	   }else{
	 	   	    rt->r = update(pos,mid+1,right,root->r,val);
	 	   }
	 	   rt->sum = rt->l->sum + rt->r->sum;
	 	   return rt;
	 }
	 int query(int left ,int right ,int L ,int R,SegNode *root){
	 	 
	 	 if(L<= left  && right  <= R){
	 	 	   return root->sum;
	 	 }
	 	 int mid= (left +right)/2;
	 	 int ret = 0;
	 	 if(L<=mid){
	 	 	 ret+= query(left,mid,L,R,root->l);
	 	 }
	 	 if(R>mid){
	 	 	 ret+= query(mid+1,right,L,R,root->r);
	 	 }
	 	 return ret;
	 }
}T;
int ql[maxn],qr[maxn],a[maxn],b[maxn];
map<int ,int >mp;
map<int, int>::iterator it;
int main(){
   int t ;
   cin >>t ;
   int cas = 0 ;
   while(~scanf("%d%d",&n,&m)){
   	cas ++ ;
       printf("Case #%d:\n",cas);
   	   mp.clear();
   	   for(int i =1;i<=n;i++){
   	   	   scanf("%d",&num[i]);
   	   	   mp[num[i]] = 1;
   	   }
   	   
   	   for(int i=1;i<=m;i++){
   	   	  scanf("%d%d%d%d",&ql[i],&qr[i],&a[i],&b[i]);
   	      mp[a[i]] =1;
   	      mp[b[i]] =1;
   	   }
   	   int tot = 0 ;
   	   for(it = mp.begin();it!= mp.end();it++){
   	   	    it->second = ++tot;
   	   }
   	   T.init();
   	   for(int i=1;i<= n;i++){
   	   	   root[i] = T.update(mp[num[i]],1,tot,root[i-1],1);
   	   }
   	   for(int i=1;i<=m;i++){
   	   //	 cout << mp[a[i]]<< "  "<<mp[b[i]] << "  "<<tot << "  "<<qr[i] <<"  "<<ql[i]<<endl;
   	   	    int ans = T.query(1,tot,mp[a[i]],mp[b[i]],root[qr[i]]) - T.query(1,tot,mp[a[i]],mp[b[i]],root[ql[i]-1]) ;
   	   	    printf("%d\n",ans);
   	   	  //  cout <<  <<endl;
   	   	 //  cout <<<<endl;
   	   }
   }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值