zoukankan      html  css  js  c++  java
  • 「专题总结」可持久化数据结构

    到了数据结构专题,心情极差。。。

    然后不出所料打的其慢。。。而且也啥都不会。。

    然后cbx,skyh和miku还故意反向奶个没完。。。极没素质

    一共才6道题。

    T1被没素质skyh和cbx大喊标签然后水过,T2差不多自己想出来了但还是颓了题解。

    T3和mikufun一起颓了标签然后yy一下就没啥了,T4听cbx喊了一个比较蠢的做法然后才在mikufun的提示下想出做法调了将近一整天。

    T5随机化水过,后来打正解WA了8发。T6被洛谷称为「模板」然后在洛谷和OJ上加起来15发才过。。。

    自闭。为什么我这么菜啊!!!烦闷死了。。。

    想也想不出来,写也写不出来,调也调不出来。。。

    唉。。。算了吧。。。先苟成什么样就是什么样了


    森林

    连边。路径第k小。强制在线。n,t<=80000

    启发式合并+主席树。被cbx颓了标签后就啥都没了。

     1 #include<cstdio>
     2 #include<algorithm>
     3 #include<map>
     4 using namespace std;
     5 map<int,int>M;
     6 #define S 80008
     7 int a[S],r[S],n,m,q,c,fir[S],l[S<<1],to[S<<1],la,f[20][S],dep[S];
     8 int rt[S],w[S<<9],lc[S<<9],rc[S<<9],cp,sz[S],RT[S],ec,pc;
     9 void link(int a,int b){l[++ec]=fir[a];fir[a]=ec;to[ec]=b;}
    10 void con(int a,int b){link(a,b);link(b,a);}
    11 void insert(int &p,int cp,int x,int cl=1,int cr=c){
    12     w[p=++pc]=w[cp]+1;
    13     if(cl==cr)return;
    14     if(x>cl+cr>>1)insert(rc[p],rc[cp],x,(cl+cr>>1)+1,cr),lc[p]=lc[cp];
    15     else insert(lc[p],lc[cp],x,cl,cl+cr>>1),rc[p]=rc[cp];
    16 }
    17 int ask(int p1,int p2,int p3,int p4,int rk,int cl=1,int cr=c){
    18     if(cl==cr)return cl;
    19     int lv=w[lc[p1]]+w[lc[p2]]-w[lc[p3]]-w[lc[p4]];
    20     if(rk<=lv)return ask(lc[p1],lc[p2],lc[p3],lc[p4],rk,cl,cl+cr>>1);
    21     return ask(rc[p1],rc[p2],rc[p3],rc[p4],rk-lv,(cl+cr>>1)+1,cr);
    22 }
    23 void dfs(int p,int fa,int r){
    24     insert(rt[p],rt[fa],M[a[p]]);RT[p]=r;sz[r]++;f[0][p]=fa;dep[p]=dep[fa]+1;
    25     for(int i=1;i<=17;++i)f[i][p]=f[i-1][f[i-1][p]];
    26     for(int i=fir[p];i;i=l[i])if(to[i]!=fa)dfs(to[i],p,r);
    27 }char o[2];
    28 int lca(int a,int b){
    29     if(dep[a]<dep[b])swap(a,b);
    30     int sub=dep[a]-dep[b];
    31     for(int i=17;~i;--i)if(sub&1<<i)a=f[i][a];
    32     for(int i=17;~i;--i)if(f[i][a]!=f[i][b])a=f[i][a],b=f[i][b];
    33     return a-b?f[0][a]:a;
    34 }
    35 int chg(int&a,int&b){if(sz[RT[a]]<sz[RT[b]])a^=b^=a^=b;}
    36 main(){
    37     scanf("%*d%d%d%d",&n,&m,&q);
    38     for(int i=1;i<=n;++i)scanf("%d",&a[i]),r[i]=a[i];
    39     sort(r+1,r+1+n);r[0]=-1;
    40     for(int i=1;i<=n;++i)if(r[i]>r[i-1])M[r[i]]=++c,r[c]=r[i];
    41     for(int i=1,x,y;i<=m;++i)scanf("%d%d",&x,&y),con(x,y);
    42     for(int i=1;i<=n;++i)if(!RT[i])dfs(i,0,i);
    43     for(int t=1,x,y,k,l;t<=q;++t){
    44         scanf("%s",o);
    45         if(o[0]=='Q')scanf("%d%d%d",&x,&y,&k),x^=la,y^=la,k^=la,l=lca(x,y),
    46             printf("%d
    ",la=r[ask(rt[x],rt[y],rt[l],rt[f[0][l]],k)]);
    47         else scanf("%d%d",&x,&y),x^=la,y^=la,con(x,y),chg(x,y),dfs(y,x,RT[x]);
    48     }
    49 }
    View Code

    影魔

    影魔,奈文摩尔,据说有着一个诗人的灵魂。事实上,他吞噬的诗人灵魂早已成千上万。千百年来,他收集了各式各样的灵魂,包括诗人、牧师、帝王、乞丐、奴隶、罪人,当然,还有英雄。每一个灵魂,都有着自己的战斗力,而影魔,靠这些战斗力提升自己的攻击。奈文摩尔有 n 个灵魂,他们在影魔宽广的体内可以排成一排,从左至右标号 1 到 n。 第 i个灵魂的战斗力为 k[i],灵魂们以点对的形式为影魔提供攻击力,对于灵魂对 i,j(i<j)来说,若不存在 ks大于 k[i]或者 k[j],则会为影魔提供 p1 的攻击力(可理解为:当 j=i+1 时,因为不存在满足 i<s<j 的 s,从而 k[s]不存在,这时提供 p1 的攻击力;当 j>i+1 时,若max{k[s]|i<s<j}<=min{k[i],k[j]} , 则 提 供 p1 的 攻击 力 ); 另 一 种 情 况 , 令 c 为k[i+1],k[i+2],k[i+3]......k[j-1]的最大值,若 c 满足:k[i]<c<k[j],或者 k[j]<c<k[i],则会为影魔提供 p2 的攻击力,当这样的 c 不存在时,自然不会提供这 p2 的攻击力;其他情况的点对,均不会为影魔提供攻击力。影魔的挚友噬魂鬼在一天造访影魔体内时被这些灵魂吸引住了,他想知道,对于任意一段区间[a,b],1<=a<b<=n,位于这些区间中的灵魂对会为影魔提供多少攻击力,即考虑 所有满足a<=i<j<=b 的灵魂对 i,j 提供的攻击力之和。顺带一提,灵魂的战斗力组成一个 1 到 n 的排列:k[1],k[2],...,k[n]。n,m<=200000

    对于90%的数据满足n=m,给我这种傻子送分。

    做法很多,之想到了一个,还不是很敢写。

    发现有关的只是两个端点的值以及它们之间的最大值三者的大小关系。

    有且只有一下几种排布情况会贡献答案。

    高低中,p1。中低高,p1。

    低中高,p2。高中低,p2。

    既然是最值问题,不难想到单调栈。

    然后既然没有强制在线,就考虑离线,把所有询问按照右端点排序后依次处理。

    从左往右扫,没有扫到的点自然不会贡献答案,这样就限制住了询问的右端点,然后再通过下标限制左端点即可。

    维护一个单调递减的栈,一个元素被弹出时就在其位置与当前枚举点$i$产生了p1贡献。(中低高)

    然后在$stack[top-1]$与$stack[top]$之间的元素,与$stack[top]$和$i$产生了p2贡献。(低中高)

    $i$入栈时,和$stack[top]$会产生p1贡献。(高低中)

    处理完点$i$就处理所有右端点为$i$的询问就可以卡住右端点,用数据结构的查询来卡住左端点。

    也就是个线段树单点/区间修改,区间查询。

    现在没考虑的贡献就是(高中低),这和(低中高)完全一样倒着跑一遍就完了。

     1 #include<cstdio>
     2 #include<algorithm>
     3 using namespace std;
     4 struct qu{int l,r,o;}q[200005];
     5 #define S 200002
     6 #define md (cl+cr>>1)
     7 int n,m,k[S],s[S],tp,P,Q;
     8 bool com(qu a,qu b){return a.r<b.r;}
     9 bool Com(qu a,qu b){return a.l>b.l;}
    10 long long w[800005],lz[800005],ans[200005];
    11 void add(int l,int r,int v,int p=1,int cl=1,int cr=n){
    12     if(r<l)return;
    13     if(l<=cl&&cr<=r){lz[p]+=v;w[p]+=v*(cr-cl+1);return;}
    14     if(l<=md)add(l,r,v,p<<1,cl,md);
    15     if(r>md)add(l,r,v,p<<1|1,md+1,cr);
    16     w[p]=w[p<<1]+w[p<<1|1];
    17 }
    18 long long ask(int l,int r,int p=1,int cl=1,int cr=n){
    19     if(l<=cl&&cr<=r)return w[p];
    20     if(lz[p])lz[p<<1]+=lz[p],lz[p<<1|1]+=lz[p],w[p<<1]+=lz[p]*(md-cl+1),w[p<<1|1]+=lz[p]*(cr-md),lz[p]=0;
    21     return (l<=md?ask(l,r,p<<1,cl,md):0)+(r>md?ask(l,r,p<<1|1,md+1,cr):0);
    22 }
    23 main(){
    24     scanf("%d%d%d%d",&n,&m,&P,&Q);
    25     for(int i=1;i<=n;++i)scanf("%d",&k[i]);
    26     for(int i=1;i<=m;++i)scanf("%d%d",&q[i].l,&q[i].r),q[i].o=i;
    27     sort(q+1,q+1+m,com);int ptr=1;
    28     for(int i=1;i<=n;++i){
    29         while(tp&&k[s[tp]]<k[i])add(s[tp],s[tp],P),add(s[tp-1]+1,s[tp]-1,Q),tp--;
    30         if(tp)add(s[tp],s[tp],P); s[++tp]=i;
    31         while(q[ptr].r==i)ans[q[ptr].o]+=ask(q[ptr].l,i),ptr++;
    32     }for(int i=1;i<=800000;++i)w[i]=lz[i]=0;
    33     sort(q+1,q+1+m,Com);ptr=1;s[tp=0]=n+1;
    34     for(int i=n;i;--i){
    35         while(tp&&k[s[tp]]<k[i])add(s[tp]+1,s[tp-1]-1,Q),tp--; s[++tp]=i;
    36         while(q[ptr].l==i)ans[q[ptr].o]+=ask(i,q[ptr].r),ptr++;
    37     }for(int i=1;i<=m;++i)printf("%lld
    ",ans[i]);
    38 }
    View Code

    世博会

    四年一度的世博会又要举办了,Q国很荣幸成为了这次世博会的主办方。Q国主席QQ从全国各地收集了N件物品排成一排,作为Q国馆的展出物。对于相邻摆放的一些物品,如果过于相似会让人觉得无聊,如果差别过大又会让人觉得突兀。为了让人们对这次世博会的展出满意,QQ需要知道一些相邻物品的“差异度”。
    为了方便表示,QQ给每个物品都定义了两个属性值A、B,两件物品之间的“绝对差异值”定义为它们对应属性的差的绝对值较大的一个。对于一些物品的“差异度”,类似求方差的方法,QQ总会首先设想一个理想的“平均物品”,它的两个属性可以为任意实数,且它与这些物品中的每个物品的“绝对差异值”之和最小。而这些物品的“差异度”就定义为这个最小的和。QQ每次会询问:从第Li个到第Ri个物品的“差异度”是多少。现在,这个任务交给了神犇你。n,q<=100000. -1e9<=A,B<=1e9

    颓了标签:切比雪夫距离转曼哈顿距离。

    即max(x,y)就是点$(frac{x+y}{2},frac{x-y}{2})$到原点的曼哈顿距离。

    说白了,就是两坐标绝对值之和。

    然后这题就没了,只要分别取区间内两坐标的中位数统计答案即可,主席树维护。

     1 #include<cstdio>
     2 #include<map>
     3 #include<algorithm>
     4 using namespace std;
     5 map<long long,int>M1,M2;
     6 int n,m,rt1[100005],rt2[100005],c[6600005],lc[6600005],rc[6600005],pc,r1[100005],r2[100005];
     7 long long w[6600005],val,s1[100005],s2[100005];
     8 void insert(int&p,int cp,int V,int v,int cl=1,int cr=n){
     9     p=++pc;lc[p]=lc[cp];rc[p]=rc[cp];w[p]=w[cp]+v;c[p]=c[cp]+1;
    10     if(cl==cr)return;
    11     if(V<=cl+cr>>1)insert(lc[p],lc[cp],V,v,cl,cl+cr>>1);else insert(rc[p],rc[cp],V,v,(cl+cr>>1)+1,cr);
    12 }
    13 long long ask(int*x,int p1,int p2,int rk,int cl=1,int cr=n){
    14     if(cl==cr)return val=x[cl],1ll*x[cl]*rk;
    15     if(c[lc[p2]]-c[lc[p1]]>=rk)return ask(x,lc[p1],lc[p2],rk,cl,cl+cr>>1);
    16     return ask(x,rc[p1],rc[p2],rk-(c[lc[p2]]-c[lc[p1]]),(cl+cr>>1)+1,cr)+w[lc[p2]]-w[lc[p1]];
    17 }
    18 int main(){
    19     scanf("%d%d",&n,&m);
    20     for(int i=1;i<=n;++i)scanf("%lld",&s1[i]);
    21     for(int i=1,x,y;i<=n;++i)x=s1[i],scanf("%d",&y),s1[i]=r1[i]=x+y,s2[i]=r2[i]=x-y;
    22     sort(r1+1,r1+1+n);sort(r2+1,r2+1+n);
    23     for(int i=1;i<=n;++i)M1[r1[i]]=i,M2[r2[i]]=i;
    24     for(int i=1;i<=n;++i)insert(rt1[i],rt1[i-1],M1[s1[i]],s1[i]),insert(rt2[i],rt2[i-1],M2[s2[i]],s2[i]);
    25     for(int i=1;i<=n;++i)s1[i]+=s1[i-1],s2[i]+=s2[i-1];
    26     for(int i=1,l,r;i<=m;++i){
    27         scanf("%d%d",&l,&r);l--;
    28         long long ans,x=ask(r1,rt1[l],rt1[r],r-l+1>>1);
    29         ans=val*(r-l+1>>1)-x+(s1[r]-s1[l]-x)-val*(r-l-(r-l+1>>1));
    30         x=ask(r2,rt2[l],rt2[r],r-l+1>>1);
    31         ans+=val*(r-l+1>>1)-x+(s2[r]-s2[l]-x)-val*(r-l-(r-l+1>>1));
    32         printf("%lld",ans>>1);puts(ans&1?".50":".00");
    33     }
    34 }
    稍卡内存,不离散化过不去

    Obserbing The Tree树上询问

    小N最近在做关于树的题。今天她想了这样一道题,给定一棵N个节点的树,节点按1~N编号,一开始每个节点上的权值都是0,接下来有M个操作。第一种操作是修改,给出4个整数X,Y,A,B,对于X到Y路径上加上一个首项是A,公差是B的等差数列,因为小N十分谨慎,所以她每做完一个修改操作就会保存一次,初始状态是第0次保存的局面。第二种操作是求和,给出2个整数X,Y,输出X到Y路径上所有节点的权值和。第三种操作是读取之前第X次保存的局面,所有节点的状态回到之前第X次保存的状态。现在请你对每一个求和操作输出答案。

    强制在线。N,M<=100000,A,B<=1000.修改<=M/2

    差分维护前缀和是可以AC的。但是直接维护也可以。

    树链剖分,主席树,标记永久化(因为要存档读档)。

    区间加一个等差数列,维护每个节点上的首项和公差就没了。

    真·难写难调。(当然cbx说它是水题啦)

     1 #include<cstdio>
     2 #define S 100002
     3 #define int long long
     4 int n,m,sz[S],hson[S],l[S<<1],to[S<<1],fir[S],ec,dfn[S],tim,top[S],dep[S],idfn[S];
     5 int nw,la,rt[S],A[S<<9],D[S<<9],lc[S<<9],rc[S<<9],w[S<<9],pc,f[S],sts;char o[4];
     6 void link(int a,int b){l[++ec]=fir[a];fir[a]=ec;to[ec]=b;}
     7 void dfs(int p,int fa){
     8     sz[p]=1;dep[p]=dep[fa]+1;f[p]=fa;
     9     for(int i=fir[p];i;i=l[i])if(to[i]!=fa){
    10         dfs(to[i],p);sz[p]+=sz[to[i]];
    11         if(sz[to[i]]>sz[hson[p]])hson[p]=to[i];
    12     }
    13 }
    14 void DFS(int p,int tp){
    15     dfn[p]=++tim;idfn[tim]=p;top[p]=tp;
    16     if(hson[p])DFS(hson[p],tp);
    17     for(int i=fir[p];i;i=l[i])if(!top[to[i]])DFS(to[i],to[i]);
    18 }
    19 int cal(int a,int d,int n){return a*n+d*(n-1)*n/2;}
    20 void add(int&p,int cp,int l,int r,int a,int d,int cl=1,int cr=n){
    21     p=++pc;lc[p]=lc[cp];rc[p]=rc[cp];A[p]=A[cp];D[p]=D[cp];
    22     if(l<=cl&&cr<=r){A[p]+=a+d*(cl-l);D[p]+=d;w[p]=w[lc[p]]+w[rc[p]]+cal(A[p],D[p],cr-cl+1);return;}
    23     if(l<=cl+cr>>1)add(lc[p],lc[cp],l,r,a,d,cl,cl+cr>>1);
    24     if(r>cl+cr>>1)add(rc[p],rc[cp],l,r,a,d,(cl+cr>>1)+1,cr);
    25     w[p]=w[lc[p]]+w[rc[p]]+cal(A[p],D[p],cr-cl+1);
    26 }
    27 int lca(int a,int b){
    28     while(top[a]!=top[b])if(dep[top[a]]>dep[top[b]])a=f[top[a]];else b=f[top[b]];
    29     return dep[a]>dep[b]?b:a;
    30 }
    31 void C(int p,int e,int a,int d){
    32     while(top[p]!=top[e])add(rt[sts],rt[nw],dfn[top[p]],dfn[p],a=a+d*(dep[p]-dep[top[p]]),-d),nw=sts,a+=d,p=f[top[p]];
    33     add(rt[sts],rt[nw],dfn[e],dfn[p],a+d*(dep[p]-dep[e]),-d);nw=sts;
    34 }
    35 void M(int x,int y,int a,int d){
    36     int z=lca(x,y);++sts;
    37     C(x,z,a,d);C(y,z,a+d*(dep[x]+dep[y]-2*dep[z]),-d);C(z,z,-(a+d*(dep[x]-dep[z])),0);
    38 }
    39 int Q(int l,int r,int p,int tla,int tld,int cl=1,int cr=n){
    40     if(l<=cl&&cr<=r)return w[p]+cal(tla,tld,cr-cl+1);int nd=tld+D[p],na=tla+A[p];
    41     return (l<=cl+cr>>1?Q(l,r,lc[p],na,nd,cl,cl+cr>>1):0)
    42         +(r>cl+cr>>1?Q(l,r,rc[p],na+nd*((cl+cr>>1)-cl+1),nd,(cl+cr>>1)+1,cr):0);
    43 }
    44 int Q(int p,int ans=0){while(p)ans+=Q(dfn[top[p]],dfn[p],rt[nw],0,0),p=f[top[p]];return ans;}
    45 main(){
    46     scanf("%lld%lld",&n,&m);
    47     for(int i=1,x,y;i<n;++i)scanf("%lld%lld",&x,&y),link(x,y),link(y,x);
    48     dfs(1,0);DFS(1,1);
    49     for(int i=1,x,y,a,d;i<=m;++i){
    50         scanf("%s",o);
    51         if(o[0]=='c')scanf("%lld%lld%lld%lld",&x,&y,&a,&d),x^=la,y^=la,M(x,y,a,d);
    52         else if(o[0]=='q')scanf("%lld%lld",&x,&y),x^=la,y^=la,d=lca(x,y),printf("%lld
    ",la=Q(x)+Q(y)-Q(d)-Q(f[d]));
    53         else scanf("%lld",&a),nw=a^la;
    54     }
    55 }
    唯一一个上2k的

    Alo

    Welcome to ALO ( Arithmetic and Logistic Online)。这是一个VR MMORPG , 如名字所见,到处充满了数学的谜题。 现在你拥有n颗宝石,每颗宝石有一个能量密度,记为ai,这些宝石的能量 密度两两不同。现在你可以选取连续的一些宝石(必须多于一个)进行融合,设为 ai, ai+1, …, a j,则融合而成的宝石的能量密度为这些宝石中能量密度的次大值 与其他任意一颗宝石的能量密度按位异或的值,即,设该段宝石能量密度次大值 为k,则生成的宝石的能量密度为max{k xor ap | ap ≠ k , i ≤ p ≤ j}。 现在你需要知道你怎么选取需要融合的宝石,才能使生成的宝石能量密度最大。n<=50000,ai<=1000000000

    啥?数据范围才50000?而且数据好像不是很好造?随便写一个可持久化trie就可以查区间次大和区间异或最大了。

    然后第一反应:这么小的数据范围,还不多测——当然随机化啦

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 int a[55555],rt[55555],w[1666666],c[2][1666666],pc,n,ans;
     4 void insert(int &p,int cp,int x,int dep=30){
     5     w[p=++pc]=w[cp]+1;
     6     if(dep==-1)return;
     7     int v=x&1<<dep?1:0;
     8     insert(c[v][p],c[v][cp],x,dep-1);c[v^1][p]=c[v^1][cp];
     9 }
    10 int sec(int p1,int p2,int rk=2,int dep=30){
    11     if(dep==-1)return 0;
    12     if(w[c[1][p2]]-w[c[1][p1]]>=rk)return sec(c[1][p1],c[1][p2],rk,dep-1)|1<<dep;
    13     return sec(c[0][p1],c[0][p2],rk-w[c[1][p2]]+w[c[1][p1]],dep-1);
    14 }
    15 int ask(int p1,int p2,int x,int dep=30){
    16     if(dep==-1)return 0;
    17     int v=x&1<<dep?0:1;
    18     if(w[c[v][p2]]-w[c[v][p1]])return ask(c[v][p1],c[v][p2],x,dep-1)|1<<dep;
    19     return ask(c[v^1][p1],c[v^1][p2],x,dep-1);
    20 }
    21 int main(){
    22     scanf("%d",&n);
    23     for(int i=1;i<=n;++i)scanf("%d",&a[i]),insert(rt[i],rt[i-1],a[i]);
    24     while(clock()<990000){
    25         int a=rand()%n+1,b=rand()%n+1;
    26         if(a==b)continue;if(a>b)a^=b^=a^=b;
    27         ans=max(ans,ask(rt[a-1],rt[b],sec(rt[a-1],rt[b])));
    28     }printf("%d
    ",ans);
    29 }
    然后就不到1k的没脸水过

    据说直接$O(n^2)$枚举是全场跑的最快的。

    但是正解还是要写的。加个线段树查询前面第一个与第二个比a[i]大的数,以它们之间的点作为左端点,以i为右端点的区间的次大值就是a[i]。

    正反跑一遍。

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 int a[55555],rt[55555],w[1666666],c[2][1666666],r[1666666],pc,n,ans,F,S,mx;
     4 map<int,int>M;
     5 void insert(int &p,int cp,int x,int dep=30){
     6     w[p=++pc]=w[cp]+1;
     7     if(dep==-1)return;
     8     int v=x&1<<dep?1:0;
     9     insert(c[v][p],c[v][cp],x,dep-1);c[v^1][p]=c[v^1][cp];
    10 }
    11 int ask(int p1,int p2,int x,int dep=30){
    12     if(dep==-1)return 0;
    13     int v=x&1<<dep?0:1;
    14     if(w[c[v][p2]]-w[c[v][p1]])return ask(c[v][p1],c[v][p2],x,dep-1)|1<<dep;
    15     return ask(c[v^1][p1],c[v^1][p2],x,dep-1);
    16 }
    17 struct Segment_Tree{
    18     int fi[200005],se[200005];
    19     void up(int x,int p){if(x>fi[p])se[p]=fi[p],fi[p]=x;else se[p]=max(se[p],x);}
    20     void chg(int pos,int x,int p=1,int cl=1,int cr=n){
    21         if(cl==cr){up(x,p);return;}
    22         if(pos<=cl+cr>>1)chg(pos,x,p<<1,cl,cl+cr>>1);
    23         else chg(pos,x,p<<1|1,(cl+cr>>1)+1,cr);
    24         fi[p]=fi[p<<1];se[p]=se[p<<1];up(se[p<<1|1],p);up(fi[p<<1|1],p);
    25     }
    26     void ask(int l,int p=1,int cl=1,int cr=n){
    27         if(cl>=l){
    28             if(se[p]>F)S=F,F=se[p];else S=max(S,se[p]);
    29             if(fi[p]>F)S=F,F=fi[p];else S=max(S,fi[p]);
    30             return;
    31         }
    32         ask(l,p<<1|1,(cl+cr>>1)+1,cr);
    33         if(l<=cl+cr>>1)ask(l,p<<1,cl,cl+cr>>1);
    34     }
    35 }T[2];
    36 main(){
    37     scanf("%d",&n);
    38     for(int i=1;i<=n;++i)scanf("%d",&a[i]),insert(rt[i],rt[i-1],a[i]),r[i]=a[i];
    39     sort(r+1,r+1+n); for(int i=1;i<=n;++i)M[r[i]]=i;
    40     for(int i=1;i<=n;++i)if(a[i]>mx)mx=a[i],T[0].chg(M[a[i]],i);
    41         else F=S=0,T[0].ask(M[a[i]]),ans=max(ans,ask(rt[S],rt[i],a[i])),T[0].chg(M[a[i]],i);
    42     mx=0;rt[n+1]=rt[n];
    43     for(int i=n;i;--i)if(a[i]>mx)mx=a[i],T[1].chg(M[a[i]],n-i+1);
    44         else F=S=0,T[1].ask(M[a[i]]),ans=max(ans,ask(rt[i],rt[n-S+1],a[i])),T[1].chg(M[a[i]],n-i+1);
    45     printf("%d
    ",ans);
    46 }
    还是比随机化好一些的

    最大异或和

    给定一个非负整数序列 {a},初始长度为 N。 有 M个操作,有以下两种操作类型:

    1. A x:添加操作,表示在序列末尾添加一个数 x,序列的长度 N+1。
    2. Q l r x:询问操作,你需要找到一个位置 p,满足 l<=p<=r,使得: a[p] xor a[p+1] xor ... xor a[N] xor x 最大,输出最大是多少。

    稍板。

     1 #include<cstdio>
     2 int n,m,rt[600005],w[20000005],c[2][20000005],pc,pre;
     3 void insert(int &p,int cp,int dep,int x){
     4     w[p=++pc]=w[cp]+1;
     5     if(dep==-1)return;
     6     int v=x&1<<dep?1:0;
     7     insert(c[v][p],c[v][cp],dep-1,x);
     8     c[v^1][p]=c[v^1][cp];
     9 }
    10 int ask(int p1,int p2,int dep,int x){
    11     if(dep==-1)return 0;
    12     int v=x&1<<dep?0:1;
    13     if(w[c[v][p2]]-w[c[v][p1]])return ask(c[v][p1],c[v][p2],dep-1,x)|1<<dep;
    14     return ask(c[v^1][p1],c[v^1][p2],dep-1,x);
    15 }char o[2];
    16 int read(){
    17     register int p=0;register char ch=getchar();
    18     while(ch<'0'||ch>'9')ch=getchar();
    19     while(ch>='0'&&ch<='9')p=(p<<3)+(p<<1)+ch-48,ch=getchar();
    20     return p;
    21 }
    22 int main(){
    23     scanf("%d%d",&n,&m);++n;
    24     insert(rt[1],rt[0],25,0);
    25     for(int i=2,x;i<=n;++i)x=read(),pre^=x,insert(rt[i],rt[i-1],25,pre);
    26     for(int i=1,x,l,r;i<=m;++i){
    27         scanf("%s",o);
    28         if(o[0]=='A')x=read(),pre^=x,++n,insert(rt[n],rt[n-1],25,pre);
    29         else l=read(),r=read(),x=read(),printf("%d
    ",ask(rt[l-1],rt[r],25,pre^x));
    30     }
    31 }
    唯一一个没上k的
  • 相关阅读:
    C#(二)变量
    WinForm(一)基础
    面向对象(二) 继承和多态
    面向对象 (三)抽象类和接口
    面向对象 基础
    面向对象(一)封装 命名空间 访问修饰符等
    C#跳转语句 迭代法 穷举法
    C# 异常处理语句
    C# while循环
    Request和Response
  • 原文地址:https://www.cnblogs.com/hzoi-DeepinC/p/12047483.html
Copyright © 2011-2022 走看看