可持久化并查集
3673:可持久化并查集 by zky
3674: 可持久化并查集加强版

const maxn1=10000100; maxn2=500000; var lson,rson,fa,deep:array[0..maxn1]of longint; root:array[0..maxn2]of longint; tot,n,m:longint; procedure swap(var x,y:longint); var i:longint; begin i:=x; x:=y; y:=i; end; procedure build(var x:longint;ll,rr:longint); var mid:longint; begin inc(tot); x:=tot; if ll=rr then begin fa[x]:=ll; exit; end; mid:=(ll+rr)>>1; build(lson[x],ll,mid); build(rson[x],mid+1,rr); end; procedure change(x,y,ll,rr,old:longint;var new:longint); var mid:longint; begin inc(tot); new:=tot; if ll=rr then begin fa[new]:=y; exit; end; mid:=(ll+rr)>>1; if x<=mid then begin rson[new]:=rson[old]; change(x,y,ll,mid,lson[old],lson[new]); end else begin lson[new]:=lson[old]; change(x,y,mid+1,rr,rson[old],rson[new]); end; end; function query(x,y,ll,rr:longint):longint; var mid:longint; begin if ll=rr then exit(x); mid:=(ll+rr)>>1; if y<=mid then exit(query(lson[x],y,ll,mid)) else exit(query(rson[x],y,mid+1,rr)) end; procedure add(x,y,ll,rr:longint); var mid:longint; begin if ll=rr then begin inc(deep[x]); exit; end; mid:=(ll+rr)>>1; if y<=mid then add(lson[x],y,ll,mid) else add(rson[x],y,mid+1,rr); end; function getfa(x,y:longint):longint; var ans:longint; begin ans:=query(x,y,1,n); if y=fa[ans] then exit(ans) else exit(getfa(x,fa[ans])) end; procedure into; begin tot:=0; readln(n,m); build(root[0],1,n); end; procedure work; var i,j,x,y,last:longint; begin last:=0; for i:=1 to m do begin read(j); root[i]:=root[i-1]; case j of 1:begin readln(x,y); x:=x xor last; y:=y xor last; x:=getfa(root[i],x); y:=getfa(root[i],y); if fa[x]<>fa[y] then begin if deep[x]>deep[y] then swap(x,y); change(fa[x],fa[y],1,n,root[i],root[i]); if deep[x]=deep[y] then add(root[i],fa[y],1,n); end; end; 2:begin readln(x); x:=x xor last; root[i]:=root[x]; end; 3:begin readln(x,y); x:=x xor last; y:=y xor last; x:=getfa(root[i],x); y:=getfa(root[i],y); if fa[x]<>fa[y] then last:=0 else last:=1; writeln(last); end; end; end; end; begin into; work; end.
【BZOJ3261】 最大异或和(可持久化trie)
然后无聊写了非递归,结果一点都不快,不开心
(算是uscao 6.1.3 cowxor 升级版?!)

const maxn1=13000010; maxn2=601000; maxd=24; var sum:array[0..maxn1]of longint; son:array[0..maxn1,0..1]of longint; num1,num2,root:array[0..maxn2]of longint; tot,n,m:longint; function addson(var x:longint):longint; begin inc(tot); x:=tot; exit(x); end; procedure insert(x,old:longint;var new:longint); var i,j,k:longint; begin addson(new); k:=new; for i:=maxd downto -1 do begin sum[new]:=sum[old]+1; if i=-1 then break; //i一定得到-1!! son[new]:=son[old]; j:=(x>>i) and 1; old:=son[old][j]; new:=addson(son[new][j]); end; new:=k; end; procedure query(x,lr,rr:longint); var i,j,ans:longint; begin ans:=0; for i:=maxd downto 0 do begin j:=(x>>i) and 1; if sum[son[rr][j xor 1]]-sum[son[lr][j xor 1]]>0 then begin ans:=ans+1<<i; lr:=son[lr][j xor 1]; rr:=son[rr][j xor 1]; end else begin lr:=son[lr][j]; rr:=son[rr][j]; end; end; writeln(ans); end; procedure into; var i:longint; begin readln(n,m); inc(n); tot:=0; insert(0,root[0],root[1]); for i:=2 to n do begin read(num1[i]); num2[i]:=num2[i-1] xor num1[i]; insert(num2[i],root[i-1],root[i]); end; readln; end; procedure work; var i,l,r,x:longint; ch:char; begin for i:=1 to m do begin read(ch); case ch of 'A':begin inc(n); readln(num1[n]); num2[n]:=num2[n-1] xor num1[n]; insert(num2[n],root[n-1],root[n]); end; 'Q':begin readln(l,r,x); query(x xor num2[n],root[l-1],root[r]); end; end; end; end; begin into; work; end.
【BZOJ3166】[Heoi2013]Alo (可持久化trie)
orz一下大神的题解
http://blog.csdn.net/oceanlight/article/details/13783591
http://hi.baidu.com/ecoecstasy/item/2b4f93dbeeb0f42438f6f748
方法是枚举每个数是次大值时,然后找出这个数作为次大值时的最大区间【l,r】,在【l,r】中算出答案。
问题一:如何求出这个数作为次大值的区间
很显然这个数如果作为次大值,有两个区间,令l1[i]=在i前比num[i]大的第一个数,l2[i]=在i前比num[i]大的第二个数,r1[i]=在i后比num[i]大的第一个数,r2[i]=在i后比num[i]大的第二个数,那么i是区间内的次大值有两个区间,一个是[l1[i]+1,r2[i]-1],另一个是[l2[i]+1,r1[i]-1]。
注意到l1[i]与l2[i]有很大关系,考虑在l1[i]基础上求l2[i]
法一,快排后解决
每个数按大小先排好,a[i]为这个数的值,b[i]为在原数列中的位置。
初始化每个值的l1[i]=i-1,r1[i]=i+1,然后按值从大到小处理,
l2[b[i]]=l1[l1[b[i]]];
r2[b[i]]=r1[r1[b[i]]];
然后改l1[b[i]]的r1为r1[b[i]],改r1[b[i]]的l1为l1[b[i]],画图试一下,就是原序列中小的数的l2,r2都算出来,那么前面指到后面,后面指到前面……
法二:单调队列
单调队列求在它前面比它大的数应该很简单吧(就是不断出队指到队尾的数比要加进的数大,此时队尾的数就是在它前面比它大的第一个数,即),然后就是找l1[i]前比它大的数,这时由于i前所有数的l1[i]以求出,就直接从j=l1[i]-1开始找l1[j]比i大的数,就是l2[i]了
问题二,求解
显然直接枚举就行了
枚举每个数作为次大值时在两个区间内(一个是[l1[i]+1,r2[i]-1],另一个是[l2[i]+1,r1[i]-1]。)所能得到的最大值……然后发现两个区间是重叠的,而且……重叠对结果没有影响(因为是在区间内取一个数),就直接查询区间[l2[i]+1,r2[i]-1],用可持久话trie解决就行了!
(特殊处理两种情况,一是在它之前没有比它大的数,显然此时就查[0,r2[i]-1],一是在它之后没有比它大的数,显然就查[l2[i]+1,n]。)
果然还是太弱,本来想对问题一用bit的……真是个蒟蒻,然后因为trie进度又被甩了几条街

const maxn1=8000000; maxn2=300000; maxd=30; var sum:array[0..maxn1]of longint; son:array[0..maxn1,0..1]of longint; num,l1,l2,r1,r2,root,p:array[0..maxn2]of longint; n,tot,mm:longint; function max(x,y:longint):longint; begin if x<y then exit(y); exit(x); end; function addson(var x:longint):longint; begin inc(tot); x:=tot; exit(x); end; procedure insert(x,old,new:longint); var i,j:longint; begin for i:=maxd downto -1 do begin sum[new]:=sum[old]+1; if i=-1 then break; son[new]:=son[old]; j:=(x>>i) and 1; old:=son[old][j]; new:=addson(son[new][j]); end; end; function query(ll,rr,x:longint):longint; var i,j,ans:longint; begin if ll>=rr then exit(0); ll:=root[ll]; rr:=root[rr]; ans:=0; for i:=maxd downto 0 do begin j:=(x>>i) and 1; if sum[son[rr][j xor 1]]-sum[son[ll][j xor 1]]>0 then begin ans:=ans+1<<i; j:=j xor 1; end; ll:=son[ll][j]; rr:=son[rr][j]; end; exit(ans); end; procedure into; var i,j,tail:longint; begin insert(0,root[0],addson(root[0])); readln(n); mm:=0; for i:=1 to n do begin read(num[i]); if num[i]>mm then mm:=num[i]; insert(num[i],root[i-1],addson(root[i])); end; tail:=0; l1[0]:=0; for i:=1 to n do begin while (tail>0) and (num[i]>=num[p[tail]]) do dec(tail); if tail=0 then l1[i]:=0 else l1[i]:=p[tail]; inc(tail); p[tail]:=i; l2[i]:=0; j:=l1[i]-1; while j>0 do if num[j]>num[i] then begin l2[i]:=j; break; end else j:=l1[j]; end; tail:=0; for i:=n downto 1 do begin while (tail>0) and (num[i]>=num[p[tail]]) do dec(tail); if tail=0 then r1[i]:=n+1 else r1[i]:=p[tail]; inc(tail); p[tail]:=i; if r1[i]=n+1 then continue; r2[i]:=n+1; j:=r1[i]+1; while j<=n do if num[j]>num[i] then begin r2[i]:=j; break; end else j:=r1[j]; end; end; procedure work; var i,ans:longint; begin ans:=0; for i:=1 to n do if num[i]<>mm then begin if r1[i]>n then r2[i]:=n+1; ans:=max(ans,query(l2[i],r2[i]-1,num[i])); end; writeln(ans); end; begin into; work; end.
2741: 【FOTILE模拟赛】L (可持久化trie)
方法类似【BZOJ3261】 最大异或和。
同样定义一个b[i]数组表示前i个数xor值。
问题为查询i属于[l,r]中a[i] xor a[i+1] xor ... xor a[j]的最大值。
然后用b[i]数组后变为b[i-1] xor b[j]的最大值。
然后如果是j固定的话就是BZOJ3261,可以在用求解,问题是j不固定,j属于[l,r]。于是……分块!
先预处理出一个dp[i,j]表示第i块块头到j的最大值。
这样[l,r]询问就可以变为[l,X)[X,r](X为l所在块的下一块块头。
[l,X)直接暴力求i属于[l,X)中的b[i-1]在区间[l,r]中能取得的xor 最大值。
[X,r]分块预处理后直接出答案。
然后就没了。
然后记得取mod!!!!

const maxn1=9000900; maxn2=50000; maxd=31; var sum:array[0..maxn1]of longint; son:array[0..maxn1,0..1]of longint; root,num:array[-1..maxn2]of longint; dp:array[0..250,0..maxn2]of longint; n,m,tot,block:longint; function calc(x:longint):longint; begin if x mod block=0 then exit(x div block) else exit(x div block+1); end; function max(x,y:longint):longint; begin if x<y then exit(y); exit(x); end; function min(x,y:longint):longint; begin if x<y then exit(x); exit(y); end; function addson(var x:longint):longint; begin inc(tot); x:=tot; exit(x); end; procedure insert(x,old,new:longint); var i,j,k:longint; begin for i:=maxd downto -1 do begin sum[new]:=sum[old]+1; if i=-1 then break; son[new]:=son[old]; j:=(x>>i) and 1; old:=son[old][j]; new:=addson(son[new][j]); end; end; function query(x,lr,rr:longint):longint; var ans,i,j:longint; begin ans:=0; for i:=maxd downto 0 do begin j:=(x>>i) and 1; if sum[son[rr][j xor 1]]-sum[son[lr][j xor 1]]>0 then begin ans:=ans+1<<i; j:=j xor 1; end; rr:=son[rr][j]; lr:=son[lr][j]; end; exit(ans); end; function getans(ll,rr:longint):longint; var l,r,ans,i:longint; begin l:=calc(ll); if l*block<rr then ans:=dp[l+1,rr] else ans:=0; for i:=ll to min(l*block,rr) do ans:=max(ans,query(num[i],root[ll],root[rr])); end; procedure into; var i,j:longint; begin read(n,m); j:=0; insert(0,root[-1],addson(root[0])); num[0]:=0; for i:=1 to n do begin read(j); num[i]:=num[i-1] xor j; insert(num[i],root[i-1],addson(root[i])); end; block:=trunc(sqrt(n)); for i:=1 to n do for j:=1 to calc(i) do dp[j,i]:=max(dp[j,i-1],query(num[i],root[(j-1)*block-1],root[i-1])); end; procedure work; var last,j,k,l:longint; begin last:=0; while m>0 do begin dec(m); readln(j,k); j:=(j+last mod n) mod n+1; //千万记得取mod k:=(k+last mod n) mod n+1; last:=getans(min(j,k)-1,max(j,k)); writeln(last); end; end; begin into; work; end.