为什么我的奇偶排序和精确调块大小是负优化啊?

P4689 [Ynoi2016] 这是我自己的发明

二楼!
by Leap_Frog @ 2020-12-30 18:30:37


奇偶排序,块长 $\frac n{\sqrt m}$,TLE 70pts ```cpp #include <iostream> #include <cstdio> #include <cstring> #include <cctype> #include <algorithm> #include <vector> #include <cmath> #define MAXN 100005 #define MAXM 5000005 using namespace std; typedef long long ll; inline int read() { int ans=0; char c=getchar(); while (!isdigit(c)) c=getchar(); while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar(); return ans; } char s[20],*tp=s; inline void write(ll x) { if (!x) return (void)(puts("0")); while (x) *(tp++)=x%10,x/=10; while (tp>s) putchar(*(--tp)+'0'); puts(""); } vector<int> e[MAXN]; int B; struct query{int l,r,pos,sgn;}q[MAXM]; inline bool operator <(const query& a,const query& b){return (a.l/B==b.l/B)? ((a.l/B)&1)^(a.r<b.r):a.l<b.l;} int a[MAXN],c[MAXN],val[MAXN],n,m,cnt; int dfn[MAXN],dep[MAXN],fa[MAXN][20],lis[MAXN],ed[MAXN],tim,rt; void dfs(int u,int f) { dep[lis[dfn[u]=++tim]=u]=dep[fa[u][0]=f]+1; for (int i=1;i<20;i++) fa[u][i]=fa[fa[u][i-1]][i-1]; for (int i=0;i<(int)e[u].size();i++) if (e[u][i]!=f) dfs(e[u][i],u); ed[u]=tim; } inline int findnxt(int x) { int y=rt; for (int i=0;(1<<i)<dep[rt]-dep[x];i++) if ((dep[rt]-dep[x]-1)&(1<<i)) y=fa[y][i]; return y; } inline bool isanc(int x,int y){return dfn[x]<=dfn[y]&&dfn[y]<=ed[x];} int cntx[MAXN],cnty[MAXN],isq[MAXM]; ll res[MAXM],pre[MAXN]; inline ll solve(int x,int y,int T) { if (y==rt) swap(x,y); if (x==rt) { if (y==rt) return pre[n]; if (isanc(y,rt)) { y=findnxt(y); return pre[n]-pre[ed[y]]+pre[dfn[y]-1]; } else return pre[ed[y]]-pre[dfn[y]-1]; } ll ans=0; int s=1,tx=isanc(x,rt),ty=isanc(y,rt); if (tx) x=findnxt(x); if (ty) y=findnxt(y); if (tx) { if (ty) ans+=pre[n]-pre[ed[y]]+pre[dfn[y]-1]; else ans+=pre[ed[y]]-pre[dfn[y]-1]; s=-s; } if (ty) ans+=s*(pre[ed[x]]-pre[dfn[x]-1]),s=-s; q[++cnt]=(query){ed[x],ed[y],T,s}; q[++cnt]=(query){dfn[x]-1,ed[y],T,-s}; q[++cnt]=(query){ed[x],dfn[y]-1,T,-s}; q[++cnt]=(query){dfn[x]-1,dfn[y]-1,T,s}; return ans; } int main() { n=read(),m=read(); for (int i=1;i<=n;i++) val[++cnt]=c[i]=read(); sort(val+1,val+cnt+1); cnt=unique(val+1,val+cnt+1)-val-1; for (int i=1;i<=n;i++) c[i]=lower_bound(val+1,val+cnt+1,c[i])-val; for (int i=1;i<n;i++) { int u,v; u=read(),v=read(); e[u].push_back(v),e[v].push_back(u); } dfs(dep[1]=rt=1,cnt=0); for (int i=1;i<=n;i++) ++cntx[a[i]=c[lis[i]]]; for (int i=1;i<=n;i++) pre[i]=pre[i-1]+cntx[a[i]]; for (int i=1;i<=n;i++) cntx[i]=0; for (int T=1;T<=m;T++) if (read()==1) rt=read(); else isq[T]=1,res[T]=solve(read(),read(),T); for (int i=1;i<=cnt;i++) (q[i].l>q[i].r)&&(swap(q[i].l,q[i].r),0); B=n/max(1,(int)sqrt(cnt)); sort(q+1,q+cnt+1); int l=0,r=0; ll ans=0; cerr<<cnt; for (int i=1;i<=cnt;i++) { while (r<q[i].r) ++cnty[a[++r]],ans+=cntx[a[r]]; while (l<q[i].l) ++cntx[a[++l]],ans+=cnty[a[l]]; while (r>q[i].r) ans-=cntx[a[r]],--cnty[a[r--]]; while (l>q[i].l) ans-=cnty[a[l]],--cntx[a[l--]]; res[q[i].pos]+=q[i].sgn*ans; } for (int i=1;i<=m;i++) (isq[i])&&(write(res[i]),0); return 0; } ``` 不奇偶排序,块长 $\sqrt n$,AC,还跑得飞快 ```cpp #include <iostream> #include <cstdio> #include <cstring> #include <cctype> #include <algorithm> #include <vector> #include <cmath> #define MAXN 100005 #define MAXM 5000005 #define re register using namespace std; typedef long long ll; inline int read() { int ans=0; char c=getchar(); while (!isdigit(c)) c=getchar(); while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar(); return ans; } char s[20],*tp=s; inline void write(ll x) { if (!x) return (void)(puts("0")); while (x) *(tp++)=x%10,x/=10; while (tp>s) putchar(*(--tp)+'0'); puts(""); } vector<int> e[MAXN]; int B; struct query{int l,r,pos,sgn;}q[MAXM]; inline bool operator <(const query& a,const query& b) { if (a.l/B==b.l/B) return a.r<b.r; return a.l<b.l; } int a[MAXN],c[MAXN],val[MAXN],n,m,cnt; int dfn[MAXN],dep[MAXN],fa[MAXN][20],lis[MAXN],ed[MAXN],tim,rt; void dfs(int u,int f) { dep[lis[dfn[u]=++tim]=u]=dep[fa[u][0]=f]+1; for (int i=1;i<20;i++) fa[u][i]=fa[fa[u][i-1]][i-1]; for (int i=0;i<(int)e[u].size();i++) if (e[u][i]!=f) dfs(e[u][i],u); ed[u]=tim; } inline int findnxt(int x) { int y=rt; for (int i=0;(1<<i)<dep[rt]-dep[x];i++) if ((dep[rt]-dep[x]-1)&(1<<i)) y=fa[y][i]; return y; } inline bool isanc(int x,int y){return dfn[x]<=dfn[y]&&dfn[y]<=ed[x];} int cntx[MAXN],cnty[MAXN],isq[MAXM]; ll res[MAXM],pre[MAXN]; inline ll solve(int x,int y,int T) { if (y==rt) swap(x,y); if (x==rt) { if (y==rt) return pre[n]; if (isanc(y,rt)) { y=findnxt(y); return pre[n]-pre[ed[y]]+pre[dfn[y]-1]; } else return pre[ed[y]]-pre[dfn[y]-1]; } ll ans=0; int s=1,tx=isanc(x,rt),ty=isanc(y,rt); if (tx) x=findnxt(x); if (ty) y=findnxt(y); if (tx) { if (ty) ans+=pre[n]-pre[ed[y]]+pre[dfn[y]-1]; else ans+=pre[ed[y]]-pre[dfn[y]-1]; s=-s; } if (ty) ans+=s*(pre[ed[x]]-pre[dfn[x]-1]),s=-s; q[++cnt]=(query){ed[x],ed[y],T,s}; q[++cnt]=(query){dfn[x]-1,ed[y],T,-s}; q[++cnt]=(query){ed[x],dfn[y]-1,T,-s}; q[++cnt]=(query){dfn[x]-1,dfn[y]-1,T,s}; return ans; } int main() { n=read(),m=read(); for (int i=1;i<=n;i++) val[++cnt]=c[i]=read(); sort(val+1,val+cnt+1); cnt=unique(val+1,val+cnt+1)-val-1; for (int i=1;i<=n;i++) c[i]=lower_bound(val+1,val+cnt+1,c[i])-val; for (int i=1;i<n;i++) { int u,v; u=read(),v=read(); e[u].push_back(v),e[v].push_back(u); } dfs(dep[1]=rt=1,cnt=0); for (int i=1;i<=n;i++) ++cntx[a[i]=c[lis[i]]]; for (int i=1;i<=n;i++) pre[i]=pre[i-1]+cntx[a[i]]; for (int i=1;i<=n;i++) cntx[i]=0; for (int T=1;T<=m;T++) if (read()==1) rt=read(); else isq[T]=1,res[T]=solve(read(),read(),T); for (int i=1;i<=cnt;i++) (q[i].l>q[i].r)&&(swap(q[i].l,q[i].r),0); B=sqrt(n); cerr<<B<<'\n'; sort(q+1,q+cnt+1); re int l=0,r=0; re ll ans=0; cerr<<cnt; for (int i=1;i<=cnt;i++) { while (r<q[i].r) ++cnty[a[++r]],ans+=cntx[a[r]]; while (l<q[i].l) ++cntx[a[++l]],ans+=cnty[a[l]]; while (r>q[i].r) ans-=cntx[a[r]],--cnty[a[r--]]; while (l>q[i].l) ans-=cnty[a[l]],--cntx[a[l--]]; res[q[i].pos]+=q[i].sgn*ans; } for (int i=1;i<=m;i++) (isq[i])&&(write(res[i]),0); return 0; } ```
by Lstdo @ 2020-12-30 18:31:54


@[Lstdo](/user/53930) 可能这道题拆出来的询问有一些奇奇怪怪的性质? 而且理论是理论,实际是实际,不能一概而论
by DPair @ 2020-12-30 18:35:10


我目前只想到这一种玄学解释。
by DPair @ 2020-12-30 18:35:28


@[Lstdo](/user/53930) 都说了那是理论,而根据数据的不同效率肯定是不同的,你还可以把块长调成 $200$ 试一下。不过奇偶优化应该是有用的啊/yun
by Gemini7X @ 2020-12-30 18:37:15


@[Lstdo](/user/53930) 你看,[块长200+奇偶优化](https://www.luogu.com.cn/record/44430387)跑得比你还快呢。
by Gemini7X @ 2020-12-30 18:40:18


@[Lstdo](/user/53930) 而且我还没开O2
by Gemini7X @ 2020-12-30 18:40:50


好像奇偶排序是排序的cmp常数太大了(?) 好玄学啊
by Lstdo @ 2020-12-30 18:41:00


精确调块长 × 玄学调块长 √
by Gemini7X @ 2020-12-30 18:43:53


@[Lstdo](/user/53930) 有个鬼的常数,一个 $nlog{n}$ 的地方你告诉我常数很大?
by Gemini7X @ 2020-12-30 18:44:47


| 下一页