标签:cte 有一个 spl lld ++ pac push 输出 线段
题目大意:让你构造一个n\le 32的有向无环无重边图,使得从1走到n的所有路径长度在L,R之间,且每种长度的路径只有唯一一条,$L,R\le 1e6$
构造图的妙妙题目
先考虑$[1,2^{k}]$的情况
利用归纳法构图
假设已经构造完$[1,2^{k}]$的图,现在要构造$[1,2^{k+1}]$的图
新点的编号为$k+3$,把编号为$2\sim k+2$的点,向$k+3$连一条长度为$2^{x-2}$的边,再把$1$和$k+3$连一条长度为$1$的边
这是把值域扩展的一个过程!$[1,k+2]$的每个点覆盖的值域就是$[1,2^{k}]$
[1,1]->[2,2] [1,2]->[3,4] [1,4]->[5,8] [1,8]->[9,16] [1,16]->[17,32] 再加上1->1
如果值域大小不是$2^{k}$,利用上面的值域覆盖的思想,我们可以再添加一个点处理$[1,S]$,最后填一个点处理$[L,R]$
1 const int N1=35; const ll inf=0x3f3f3f3f3f3f3f3fll; 2 3 int L,R; 4 int n,m,len; 5 int mp[N1][N1]; 6 7 int main() 8 { 9 freopen("a.in","r",stdin); 10 scanf("%d%d",&L,&R); len=R-L+1; 11 mp[1][2]=1; 12 while((1<<(n+1))<=len) n++; n+=2; 13 for(int k=0;k<=n-3;k++) 14 { 15 mp[1][k+3]=1; 16 for(int j=2;j<=k+2;j++) mp[j][k+3]=(1<<(j-2)); 17 } 18 int tmp=len; 19 if(len!=(1<<(n-2))) 20 { 21 for(int k=n-2;k>=1;k--) 22 { 23 if(tmp>(1<<k)) 24 { 25 mp[k+2][n+1]=tmp-(1<<k); 26 tmp-=(1<<k); 27 } 28 if(!tmp) break; 29 } 30 if(tmp==1) mp[1][n+1]=1, tmp--; 31 else if(tmp==2) mp[1][n+1]=1, mp[2][n+1]=1, tmp-=2; 32 n++; 33 } 34 if(L!=1) 35 { 36 mp[n][n+1]=L-1; 37 n++; 38 } 39 for(int i=1;i<=n;i++) for(int j=i+1;j<=n;j++) if(mp[i][j]) m++; 40 printf("YES \n%d %d\n",n,m); 41 for(int i=1;i<=n;i++) for(int j=i+1;j<=n;j++) if(mp[i][j]) 42 { 43 printf("%d %d %d \n",i,j,mp[i][j]); 44 } 45 return 0; 46 }
题目大意:给你一棵树,每个点有一个权值,有$Q$个询问,每次输出$x,y$简单路径上任意一个$[L,R]$内且出现次数为奇数次的权值$N,Q\le 3e5$
最容易想到的就是树上莫队了,然而$O(n\sqrt n)$会被卡掉 也可能是我常数大
1 using namespace std; 2 const int N1=600005; const ll inf=0x3f3f3f3f3f3f3f3fll; 3 4 template<typename _T> void read(_T &ret) 5 { 6 ret=0; _T fh=1; char c=getchar(); 7 while(c<‘0‘||c>‘9‘){ if(c==‘-‘) fh=-1; c=getchar(); } 8 while(c>=‘0‘&&c<=‘9‘){ ret=ret*10+c-‘0‘; c=getchar(); } 9 ret=ret*fh; 10 } 11 template<typename _T> void out(_T ret) 12 { 13 if(ret) out(ret/10); else return ; 14 putchar(ret%10+‘0‘); 15 } 16 struct EDGE{ 17 int to[N1],nxt[N1],head[N1],cte; 18 void ae(int u,int v) 19 { cte++; to[cte]=v; nxt[cte]=head[u]; head[u]=cte; } 20 }e; 21 22 int n,nn,Q,sq,S,P; 23 int a[N1],st[N1],ed[N1],tot,pos[N1],type[N1]; 24 int ids[N1],idp[N1]; 25 26 struct QUES{ 27 int lp,rp,x,y,f,l,r,id,ans; 28 }qu[N1]; 29 int cmp0(QUES aa,QUES bb) 30 { 31 if(ids[aa.lp]==ids[bb.lp]) return ids[aa.rp]<ids[bb.rp]; 32 else return ids[aa.lp]<ids[bb.lp]; 33 } 34 int cmp1(QUES aa,QUES bb) 35 { 36 return aa.id<bb.id; 37 } 38 39 int ff[N1][20],dep[N1]; 40 void dfs0(int u,int fa) 41 { 42 st[u]=++tot; pos[tot]=u; type[tot]=1; 43 for(int j=e.head[u];j;j=e.nxt[j]) 44 { 45 int v=e.to[j]; if(v==fa) continue; 46 ff[v][0]=u; dep[v]=dep[u]+1; dfs0(v,u); 47 } 48 ed[u]=++tot; pos[tot]=u; type[tot]=-1; 49 } 50 void getfa() 51 { 52 for(int j=1;j<=18;j++) 53 for(int i=1;i<=n;i++) 54 ff[i][j]=ff[ff[i][j-1]][j-1]; 55 } 56 int lca(int x,int y) 57 { 58 if(dep[x]<dep[y]) swap(x,y); 59 for(int j=18;j>=0;j--) if(dep[ff[x][j]]>=dep[y]) 60 x=ff[x][j]; 61 if(x==y) return x; 62 int ans=0; 63 for(int j=18;j>=0;j--) 64 { 65 if(ff[x][j]!=ff[y][j]) x=ff[x][j], y=ff[y][j]; 66 else ans=ff[x][j]; 67 } 68 return ans; 69 } 70 71 int num[N1],sum[N1],vis[N1]; 72 int L,R; 73 void upd(int w,int p) 74 { 75 num[w]+=p; 76 if(num[w]&1) sum[idp[w]]++; else sum[idp[w]]--; 77 } 78 void pushx(int y) 79 { 80 if(vis[pos[y]]) upd(a[pos[y]],-1), vis[pos[y]]=0; 81 else upd(a[pos[y]],1), vis[pos[y]]=1; 82 } 83 int solve(int q) 84 { 85 int x=qu[q].x, y=qu[q].y, lw=qu[q].l ,rw=qu[q].r, F=qu[q].f; 86 sta=clock(); 87 if(x!=F&&y!=F) pushx(st[F]); 88 for(;R<qu[q].rp;R++) pushx(R+1); 89 for(;qu[q].lp<L;L--) pushx(L-1); 90 for(;qu[q].rp<R;R--) pushx(R); 91 for(;L<qu[q].lp;L++) pushx(L); 92 End=clock(); tt0+=End-sta; 93 94 sta=clock(); 95 if(idp[lw]==idp[rw]){ 96 for(int i=lw;i<=rw;i++) if(num[i]&1) return i; 97 }else{ 98 for(int i=lw;i<=idp[lw]*P;i++) if(num[i]&1) return i; 99 for(int i=(idp[rw]-1)*P+1;i<=rw;i++) if(num[i]&1) return i; 100 for(int i=idp[lw]+1;i<=idp[rw]-1;i++) if(sum[i]>=1) 101 for(int j=(i-1)*P+1;j<=i*P;j++) if(num[j]&1) return j; 102 } 103 return -1; 104 } 105 106 int main() 107 { 108 freopen("a.txt","r",stdin); 109 freopen("a0.out","w",stdout); 110 scanf("%d%d",&n,&Q); 111 nn=2*n; P=sqrt(n); S=1000; 112 for(int i=1;i<=n;i++) read(a[i]); 113 for(int i=1;i<=n;i++) idp[i]=(i-1)/P+1; 114 for(int i=1;i<=nn;i++) ids[i]=(i-1)/S+1; 115 int x,y,F; 116 for(int i=1;i<n;i++) read(x), read(y), e.ae(x,y), e.ae(y,x); 117 dep[1]=1; dfs0(1,0); getfa(); 118 for(int q=1;q<=Q;q++) 119 { 120 read(x), read(y), read(qu[q].l), read(qu[q].r); qu[q].id=q; 121 F=lca(x,y); qu[q].f=F; 122 if(x==F) qu[q].lp=st[x], qu[q].rp=st[y]; 123 else if(y==F) qu[q].lp=st[y], qu[q].rp=st[x]; 124 else{ 125 if(st[x]>st[y]) swap(x,y); 126 qu[q].lp=ed[x], qu[q].rp=st[y]; 127 } 128 qu[q].x=x, qu[q].y=y; 129 } 130 sort(qu+1,qu+Q+1,cmp0); 131 L=nn+1,R=nn+1; 132 for(int q=1;q<=Q;q++) 133 { 134 x=qu[q].x, y=qu[q].y; //l=qu[q].l, r=qu[q].r; 135 qu[q].ans=solve(q); 136 if(x!=qu[q].f&&y!=qu[q].f) pushx(st[qu[q].f]); 137 End=clock(); tt1+=End-sta; 138 } 139 sort(qu+1,qu+Q+1,cmp1); 140 for(int q=1;q<=Q;q++) 141 if(qu[q].ans<0) puts("-1"); 142 else out(qu[q].ans), puts(""); 143 return 0; 144 }
题解提供了一种成功率很高的随机化异或做法
考虑把点权等距拉长到$[1,2^{64}]$,维护路径的异或和
拉长后,异或碰撞,即异或和为$0$但存在出现奇数次的权值的概率非常低,是1/值域,$Q$次询问也不会有多大影响
主席树维护$f(1,x,l,r)$表示$1$到$x$路径上所有点权在$l,r$范围内的异或和,线段树二分找答案
1 using namespace std; 2 const int N1=300005; const int M1=N1*66; const ll inf=0x3f3f3f3f3f3f3f3fll; 3 4 template<typename _T> void read(_T &ret) 5 { 6 ret=0; _T fh=1; char c=getchar(); 7 while(c<‘0‘||c>‘9‘){ if(c==‘-‘) fh=-1; c=getchar(); } 8 while(c>=‘0‘&&c<=‘9‘){ ret=ret*10+c-‘0‘; c=getchar(); } 9 ret=ret*fh; 10 } 11 template<typename _T> void out(_T ret) 12 { 13 if(ret) out(ret/10); else return ; 14 putchar(ret%10+‘0‘); 15 } 16 struct EDGE{ 17 int to[N1*2],nxt[N1*2],head[N1],cte; 18 void ae(int u,int v) 19 { cte++; to[cte]=v; nxt[cte]=head[u]; head[u]=cte; } 20 }e; 21 struct SEG{ 22 int ls[M1],rs[M1],root[N1],tot; ll xsum[M1]; 23 void upd(ll x,ll l,ll r,int r1,int &r2) 24 { 25 if(!r2||r1==r2){ r2=++tot; ls[r2]=ls[r1]; rs[r2]=rs[r1]; xsum[r2]=xsum[r1]^x; } 26 if(l==r) return; 27 ll mid=(l+r)>>1; 28 if(x<=mid) upd(x,l,mid,ls[r1],ls[r2]); 29 else upd(x,mid+1,r,rs[r1],rs[r2]); 30 } 31 inline ll calc(int r1,int r2,int r3,int r4) 32 { return xsum[r1]^xsum[r2]^xsum[r3]^xsum[r4]; } 33 ll query(ll L,ll R,ll l,ll r,int r1,int r2,int r3,int r4) 34 { 35 ll mid=(l+r)>>1; 36 if(l==r) return calc(r1,r2,r3,r4); 37 if(L<=l&&r<=R) 38 { 39 if(!calc(r1,r2,r3,r4)) return 0; 40 if(calc(ls[r1],ls[r2],ls[r3],ls[r4])) return query(L,R,l,mid,ls[r1],ls[r2],ls[r3],ls[r4]); 41 else return query(L,R,mid+1,r,rs[r1],rs[r2],rs[r3],rs[r4]); 42 } 43 ll ans=0; 44 if(L<=mid&&!ans) ans=query(L,R,l,mid,ls[r1],ls[r2],ls[r3],ls[r4]); 45 if(R>mid&&!ans) ans=query(L,R,mid+1,r,rs[r1],rs[r2],rs[r3],rs[r4]); 46 return ans; 47 } 48 }s; 49 50 int n,Q; 51 int a[N1]; 52 map<ll,int>real; ll tra[N1]; 53 54 int ff[N1][20],dep[N1]; 55 void dfs0(int u,int fa) 56 { 57 for(int j=e.head[u];j;j=e.nxt[j]) 58 { 59 int v=e.to[j]; if(v==fa) continue; 60 ff[v][0]=u; dep[v]=dep[u]+1; 61 s.upd(tra[a[v]],1,inf,s.root[u],s.root[v]); 62 dfs0(v,u); 63 } 64 } 65 void getfa() 66 { 67 for(int j=1;j<=18;j++) 68 for(int i=1;i<=n;i++) 69 ff[i][j]=ff[ff[i][j-1]][j-1]; 70 } 71 int lca(int x,int y) 72 { 73 if(dep[x]<dep[y]) swap(x,y); 74 for(int j=18;j>=0;j--) if(dep[ff[x][j]]>=dep[y]) 75 x=ff[x][j]; 76 if(x==y) return x; 77 int ans=0; 78 for(int j=18;j>=0;j--) 79 { 80 if(ff[x][j]!=ff[y][j]) x=ff[x][j], y=ff[y][j]; 81 else ans=ff[x][j]; 82 } 83 return ans; 84 } 85 86 int main() 87 { 88 sta=clock(); 89 scanf("%d%d",&n,&Q); 90 for(int i=1;i<=n;i++) read(a[i]); 91 for(int i=1;i<=n;i++) tra[i]=inf/n*i, real[inf/n*i]=i; 92 int x,y,l,r,F; ll ans; 93 for(int i=1;i<n;i++) read(x), read(y), e.ae(x,y), e.ae(y,x); 94 dep[1]=1; s.upd(tra[a[1]],1,inf,0,s.root[1]); 95 dfs0(1,0); getfa(); 96 97 for(int q=1;q<=Q;q++) 98 { 99 read(x), read(y), read(l), read(r); 100 F=lca(x,y); 101 ans=s.query(tra[l],tra[r],1,inf,s.root[x],s.root[y],s.root[F],s.root[ff[F][0]]); 102 if(!ans) ans=-1; else ans=real[ans]; 103 printf("%lld\n",ans); 104 } 105 return 0; 106 }
标签:cte 有一个 spl lld ++ pac push 输出 线段
原文地址:https://www.cnblogs.com/guapisolo/p/14407686.html