• [洛谷P4585] [FJOI2015] 火星商店问题


    Description

    火星上的一条商业街里按照商店的编号 (1)(2) ,…,(n) ,依次排列着 (n) 个商店。商店里出售的琳琅满目的商品中,每种商品都用一个非负整数 (val) 来标价。每个商店每天都有可能进一些新商品,其标价可能与已有商品相同。

    火星人在这条商业街购物时,通常会逛这条商业街某一段路上的所有商店,譬如说商店编号在区间 ([L,R]) 中的商店,从中挑选1件自己最喜欢的商品。每个火星人对商品的喜好标准各不相同。通常每个火星人都有一个自己的喜好密码 (x) 。对每种标价为 (val) 的商品,喜好密码为 (x) 的火星人对这种商品的喜好程度与 (val) 异或 (x) 的值成正比。也就是说,(val) (xor) (x) 的值越大,他就越喜欢该商品。每个火星人的购物卡在所有商店中只能购买最近 (d) 天内(含当天)进货的商品。另外,每个商店都有一种特殊商品不受进货日期限制,每位火星人在任何时刻都可以选择该特殊商品。每个商店中每种商品都能保证供应,不存在商品缺货的问题。

    对于给定的按时间顺序排列的事件,计算每个购物的火星人的在本次购物活动中最喜欢的商品,即输出 (val) (xor) (x) 的最大值。这里所说的按时间顺序排列的事件是指以下 (2) 种事件:

    事件 (0), 用三个整数 (0) , (s) , (v) ,表示编号为 (s) 的商店在当日新进一种标价为 (v) 的商品。

    事件 (1),用 (5) 个整数 (1) , $ L$ , (R) , (x) , (d) ,表示一位火星人当日在编号为 (L)(R) 的商店购买 (d) 天内的商品,该火星人的喜好密码为 (x)

    Input

    第1行中给出2个正整数 (n) , (m) ,分别表示商店总数和事件总数。

    第2行中有 (n) 个整数,第 (i) 个整数表示商店 (i) 的特殊商品标价。

    接下来的 (m) 行,每行表示 (1) 个事件。每天的事件按照先事件 (0), 后事件 (1) 的顺序排列。

    Output

    将计算出的每个事件 (1)(val) (xor) (x) 的最大值依次输出。

    Sample Input

    4 6
    1 2 3 4
    1 1 4 1 0
    0 1 4
    0 1 3
    1 1 1 1 0
    1 1 1 1 1
    1 1 2 1 2

    Sample Output

    5
    0
    2
    5

    HINT

    (n, m leq 100000)

    数据中,价格不大于 (100000)


    想法

    首先吐槽题面!没见过比它说得更不清楚更恶心的了。。。
    “每天”的定义:出现事件0 就是新一天的开始,在第一个事件0出现前的事件可看作第0天的。

    要求异或和最大有两种方法,一种是线性基,一种是可持久化 (trie) ,这道题中可持久化 (trie) 更方便。
    对于不受时间限制的特殊商品,直接以商店编号为版本号建一个 可持久化 (trie) ,查询、更新答案。
    其他操作咋一看好像很复杂。
    但如果商店编号当作 (x) 轴,时间当作 (y) 轴,其实就是 添加单点+二维矩阵查询与 (x) 的最大异或和。

    那就需要树套树(线段树+可持久化 (trie))了。
    以商店编号为下标建线段树,在线段树每个节点以时间为版本号建 可持久化 (trie) (反过来也行啦~)
    但如果这样空间受不住。

    于是线段树分治。
    将每个每个查询拆成 (O(logn)) 份放到线段树节点上
    遍历线段树的每个节点,现场建树、查询、更新答案。

    总复杂度 (O(nlog^2n))


    代码

    这代码……不太好写也不太好调。
    唯一的安慰是数据弱,调过样例后就 (1A) 了。
    (ps) 指针选手似乎变为数组选手了呢……)

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    #include<vector>
    #include<cstring>
    
    using namespace std;
    
    int read(){
    	int x=0;
    	char ch=getchar();
    	while(!isdigit(ch)) ch=getchar();
    	while(isdigit(ch)) x=x*10+ch-'0',ch=getchar();
    	return x;
    }
    
    const int N = 100005;
    
    struct commo{ int x,d; };
    struct query{ int x,l,r,id; };
    int n,m;
    int spi[N],ans[N];
    
    int rt[N],cnt2,son[N*20][2],sum[N*20];
    void clear(int x){
    	for(int i=0;i<cnt2;i++) son[i][0]=son[i][1]=0,sum[i]=0;
    	cnt2=0; 
    	for(int i=0;i<=x;i++) rt[i]=0;
    	if(x==-1) memset(rt,0,sizeof(rt));
    }
    void insert(int x,int pre,int dep,int c){
    	if(dep==-1) { sum[x]=sum[pre]+1; return; }
    	int f=((c>>dep)&1);
    	son[x][f^1]=son[pre][f^1];
    	insert(son[x][f]=++cnt2,son[pre][f],dep-1,c);
    	sum[x]=sum[pre]+1;
    }
    int ask(int x,int pre,int dep,int c){
    	if(dep==-1) return 0;
    	int f=((c>>dep)&1); 
    	if(sum[son[x][f^1]]>sum[son[pre][f^1]]) return (1<<dep)+ask(son[x][f^1],son[pre][f^1],dep-1,c);
    	return ask(son[x][f],son[pre][f],dep-1,c);
    }
    
    int root,cnt;
    int ch[N*2][2];
    vector<commo> v[N*2];
    vector<query> q[N*2];
    void build(int x,int l,int r){
    	if(l==r) return;
    	int mid=(l+r)>>1;
    	build(ch[x][0]=++cnt,l,mid);
    	build(ch[x][1]=++cnt,mid+1,r);
    }
    void modify(int x,int l,int r,int c,commo d){
    	v[x].push_back(d);
    	if(l==r) return;
    	int mid=(l+r)>>1;
    	if(c<=mid) modify(ch[x][0],l,mid,c,d);
    	else modify(ch[x][1],mid+1,r,c,d);
    }
    void add(int x,int l,int r,int L,int R,query d){
    	if(l>=L && r<=R) { q[x].push_back(d); return; }
    	int mid=(l+r)>>1;
    	if(R>mid) add(ch[x][1],mid+1,r,L,R,d);
    	if(L<=mid) add(ch[x][0],l,mid,L,R,d);
    }
    
    int b[N],tot;
    void work(int x,int l,int r){
    	if(q[x].size()){
    		tot=0;
    		for(int i=0;i<v[x].size();i++) b[++tot]=v[x][i].d;
    		sort(b+1,b+1+tot);
    		tot=unique(b+1,b+1+tot)-b-1; 
    		for(int i=0;i<v[x].size();i++){
    			int id=lower_bound(b+1,b+1+tot,v[x][i].d)-b,pre;
    			pre=(rt[id] ? rt[id] : rt[id-1]);
    			insert(rt[id]=++cnt2,pre,17,v[x][i].x);
    		}
    		
    		for(int i=0;i<q[x].size();i++){
    			if(q[x][i].l>q[x][i].r) continue;
    			int ll=lower_bound(b+1,b+1+tot,q[x][i].l)-b-1,rr=upper_bound(b+1,b+1+tot,q[x][i].r)-b-1;
    			if(ll<rr) {
    				ans[q[x][i].id]=max(ans[q[x][i].id],ask(rt[rr],rt[ll],17,q[x][i].x));
    			}
    		}
    		
    		clear(tot);
    	}
    	
    	if(l==r) return;
    	int mid=(l+r)>>1;
    	work(ch[x][0],l,mid); work(ch[x][1],mid+1,r);
    }
    
    int main()
    {
    	n=read(); m=read();
    	for(int i=1;i<=n;i++) spi[i]=read();
    	
    	clear(-1);
    	for(int i=1;i<=n;i++)
    		insert(rt[i]=++cnt2,rt[i-1],17,spi[i]);
    	
    	int opt,day=1,ques=0,l,r,d,x;
    	build(root=++cnt,1,n);
    	for(int i=0;i<m;i++){
    		opt=read();
    		if(opt==0) {
    			l=read(); x=read();
    			modify(root,1,n,l,(commo){x,++day});
    		}
    		else{
    			l=read(); r=read(); x=read(); d=read();
    			add(root,1,n,l,r,(query){x,max(day-d+1,1),day,ques++});
    			ans[ques-1]=ask(rt[r],rt[l-1],17,x);
    		}
    	}
    	clear(n);
    	
    	work(root,1,n);
    	for(int i=0;i<ques;i++) printf("%d
    ",ans[i]);
    	
    	return 0;
    } 
    
    既然选择了远方,便只顾风雨兼程
  • 相关阅读:
    Vue双向绑定的实现原理系列(一):Object.defineproperty
    TCP协议中的三次握手和四次挥手
    一切事物皆对象_进阶篇
    一切事物皆对象_基础篇
    自成一派的正则表达式
    超好用的模块
    软件目录开发规范
    迭代器与生成器
    不怎么好吃的语法糖
    你可造什么是函数
  • 原文地址:https://www.cnblogs.com/lindalee/p/11371832.html
Copyright © 2020-2023  润新知