【以前的空间】可持久化题目

可持久化并查集
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.
View Code

【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.
View Code

 

【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.
View Code

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.
View Code
原文地址:https://www.cnblogs.com/Macaulish/p/6492148.html