【十二省联考2019】异或粽子/可持久化01trie

可持久化01trie支持查询最大的区间异或和。

对于普通01trie,我们每次新建的是一条新边(也有可能不建)

而可持久化01trie就像主席树一样,每次利用历史版本新建。

一般学到可持久化01trie的都学过主席树了吧,所以我就不讲思想了

 1 struct tree{
 2     LL ch[2],id,cnt;
 3 }tr[N*50];
 4 LL tot=0;
 5 
 6 void Insert(LL co,LL &now,LL k,LL pos,LL bit){
 7     // 历史版本,新建的树,数值,原序列中的位置,当前高度 
 8     tr[now=++tot]=tr[co];//新建节点 
 9     ++tr[now].cnt;//++次数 
10     if(bit<0){tr[now].id=pos;return;}
11     bool c=k&(1LL<<bit);//一定要用bool,RE的血泪史。 
12     Insert(tr[co].ch[c],tr[now].ch[c],k,pos,bit-1);
13     return;
14 }
15 
16 inline LL query(LL l,LL r,LL k,LL bit){
17     //     左边界,右边界,数值,高度 
18     if(bit<0)return tr[r].id;
19     bool c=k&(1<<bit);
20     LL rem=tr[tr[r].ch[c^1]].cnt-tr[tr[l].ch[c^1]].cnt;
21     if(rem)return query(tr[l].ch[c^1],tr[r].ch[c^1],k,bit-1);
22     else return query(tr[l].ch[c],tr[r].ch[c],k,bit-1);
23     //贪心的选取c^1,实在没得选也就只能走c了 
24 }

例题:异或粽子

对于一个起点 i ,找到它与 sum[ (i,n] ] 异或的最大位置,记为pos。

开一个结构体

1 struct D{
2     LL st;
3     LL l,r,pos;//pos可选的区间
4     LL sum;//这个可以不用存
5     bool operator < (D b) const{
6         return sum<b.sum;
7     }
8 };

压到大根堆里,每次取出最大的,然后把 [ l , r ] 从pos那里分成两个区间,分别算出pos再压进去。

重复k次。

代码写的很仓促,某谷会TLE两个点,仅供参考。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<string>
 4 #include<cstring>
 5 #include<queue>
 6 #include<cctype>
 7 using namespace std;
 8 #define LL long long
 9 const int N=500005;
10 LL n,x,k;
11 LL sum[N];
12 struct tree{
13     LL ch[2],id,cnt;
14 }tr[N*50];
15 LL rt[N];
16 LL tot=0;
17 void Insert(LL co,LL &now,LL k,LL pos,LL bit){
18     // 历史版本,新建的树,数值,原序列中的位置,当前高度 
19     tr[now=++tot]=tr[co];//新建节点 
20     ++tr[now].cnt;//++次数 
21     if(bit<0){tr[now].id=pos;return;}
22     bool c=k&(1LL<<bit);//一定要用bool,RE的血泪史。 
23     Insert(tr[co].ch[c],tr[now].ch[c],k,pos,bit-1);
24     return;
25 }
26 
27 inline LL query(LL l,LL r,LL k,LL bit){
28     //     左边界,右边界,数值,高度 
29     if(bit<0)return tr[r].id;
30     bool c=k&(1<<bit);
31     LL rem=tr[tr[r].ch[c^1]].cnt-tr[tr[l].ch[c^1]].cnt;
32     if(rem)return query(tr[l].ch[c^1],tr[r].ch[c^1],k,bit-1);
33     else return query(tr[l].ch[c],tr[r].ch[c],k,bit-1);
34     //贪心的选取c^1,实在没得选也就只能走c了 
35 }
36 
37 struct D{
38     LL st;
39     LL l,r,pos;
40     LL sum;
41     bool operator < (D b) const{
42         return sum<b.sum;
43     }
44 };
45 
46 priority_queue<D> q;
47 
48 LL ans=0;
49 
50 int main(){
51     //freopen("1.in","r",stdin);
52     scanf("%lld%lld",&n,&k);
53     for(LL i=1;i<=n;++i){
54         scanf("%lld",&x);
55         sum[i]=sum[i-1]^x;
56     }
57     for(LL i=1;i<=n;++i){
58         Insert(rt[i-1],rt[i],sum[i],i,33);
59     }
60     for(LL i=1;i<=n;++i){
61         LL l=i;
62         LL r=query(rt[l-1],rt[n],sum[l-1],33);
63         q.push((D){l,l,n,r,sum[r]^sum[l-1]});
64     }
65     while(k--){
66         D tmp=q.top();q.pop();
67         ans+=tmp.sum;
68         LL st=tmp.st;
69         LL i=tmp.l,j=tmp.r;
70         if(i<tmp.pos){
71             LL t=query(rt[i-1],rt[tmp.pos-1],sum[st-1],33);
72             q.push((D){st,i,tmp.pos-1,t,sum[t]^sum[st-1]});
73         }
74         if(j>tmp.pos){
75             LL t=query(rt[tmp.pos],rt[j],sum[st-1],33);
76             q.push((D){st,tmp.pos+1,j,t,sum[st-1]^sum[t]});
77         }
78     }
79     cout<<ans;
80     return 0;
81 }

猜你喜欢

转载自www.cnblogs.com/chiyo/p/11209325.html