https://www.luogu.org/problemnew/show/P3603
https://www.lydsy.com/JudgeOnline/problem.php?id=4763
就是先树分块,取所有的块顶为关键点
那么任意点与它祖先中离它最近的关键点的距离为根号级别
先预处理出任意两个关键点之间的路径上有的值的bitset
(vv[i][j][k]表示i到j的路径上是否出现值k)
那么,只需要在询问时,对于路径(a,b),得到它路径上有的值的bitset;对于每个询问,把所有得到的bitset或一下就行了
得到bitset的方法见代码。。。
以下代码常数超大!为了卡常特意手写了bitset,还把块大小改到550(不是根号,实测这样更快...)
1 #pragma GCC optimize(3) 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 #include<vector> 6 #include<bitset> 7 using namespace std; 8 #define fi first 9 #define se second 10 #define mp make_pair 11 #define pb push_back 12 typedef long long ll; 13 typedef unsigned long long ull; 14 typedef pair<int,int> pii; 15 int n,m,F; 16 vector<int> e[100100]; 17 int dd[100100]; 18 const int bsz=480; 19 ull lft[64]; 20 void init() 21 { 22 lft[0]=1; 23 for(int i=1;i<64;i++) lft[i]=lft[i-1]<<1; 24 } 25 struct bs 26 { 27 ull d[bsz]; 28 int _Find_first_zero() 29 { 30 for(int i=0;i<bsz;i++) 31 if(d[i]!=0xffffffffffffffff) 32 return (i<<6)+__builtin_ffsll(~d[i])-1; 33 } 34 void reset() 35 { 36 for(int i=0;i<bsz;i++) d[i]=0; 37 } 38 void set(int p,bool q=1) 39 { 40 if(q) d[p>>6]|=lft[p-((p>>6)<<6)]; 41 else d[p>>6]&=~lft[p-((p>>6)<<6)]; 42 } 43 int count() 44 { 45 int ans=0; 46 for(int i=0;i<bsz;i++) ans+=__builtin_popcountll(d[i]); 47 return ans; 48 } 49 bs &operator|=(const bs &b) 50 { 51 for(int i=0;i<bsz;i++) d[i]|=b.d[i]; 52 return *this; 53 } 54 }; 55 int bl[100100],rt[310],cnt; 56 const int sz=550; 57 namespace GBLOCK 58 { 59 int st[100100],tp; 60 void dfs(int u,int fa) 61 { 62 int i,ltp=tp; 63 for(i=0;i<e[u].size();i++) 64 if(e[u][i]!=fa) 65 { 66 dfs(e[u][i],u); 67 if(tp-ltp>=sz) 68 { 69 rt[++cnt]=u; 70 while(tp!=ltp) bl[st[tp--]]=cnt; 71 } 72 } 73 st[++tp]=u; 74 } 75 void work() 76 { 77 dfs(1,0); 78 ++cnt;rt[cnt]=1; 79 while(tp) bl[st[tp--]]=cnt; 80 } 81 } 82 namespace LCA 83 { 84 int anc[100100][20],dep[100100],l2n=19; 85 void dfs(int u,int fa) 86 { 87 int i; 88 anc[u][0]=fa; 89 dep[u]=dep[fa]+1; 90 for(i=1;i<=l2n;i++) 91 anc[u][i]=anc[anc[u][i-1]][i-1]; 92 for(i=0;i<e[u].size();i++) 93 if(e[u][i]!=fa) 94 dfs(e[u][i],u); 95 } 96 int lca(int x,int y) 97 { 98 int t,i; 99 if(dep[x]<dep[y]){t=x;x=y;y=t;} 100 for(t=dep[x]-dep[y],i=0;t>0;t>>=1,i++) 101 if(t&1) x=anc[x][i]; 102 if(x==y) return x; 103 for(i=l2n;i>=0;i--) 104 if(anc[x][i]!=anc[y][i]) 105 { 106 x=anc[x][i]; 107 y=anc[y][i]; 108 } 109 return anc[x][0]; 110 } 111 } 112 using LCA::lca; 113 using LCA::dep; 114 using LCA::anc; 115 int nn[100100],nnn; 116 bs vv[310][310];//vv[i][j]:rt[i],rt[j]间答案 117 int num[30100];bs vis; 118 namespace PRE 119 { 120 int s; 121 void dfs(int u,int fa) 122 { 123 int i; 124 if(!num[dd[u]]) vis.set(dd[u]); 125 ++num[dd[u]]; 126 if(nn[u]) vv[s][nn[u]]=vis; 127 for(i=0;i<e[u].size();i++) 128 if(e[u][i]!=fa) 129 dfs(e[u][i],u); 130 --num[dd[u]]; 131 if(!num[dd[u]]) vis.set(dd[u],0); 132 } 133 void work() 134 { 135 int i; 136 for(i=1;i<=cnt;i++) 137 if(!nn[rt[i]]) 138 nn[rt[i]]=++nnn; 139 for(i=1;i<=n;i++) 140 if(nn[i]) 141 { 142 s=nn[i]; 143 dfs(i,0); 144 } 145 } 146 } 147 bs tt; 148 void jump1(int &x,int ed) 149 { 150 if(ed==-1) ed=rt[bl[x]]; 151 while(x!=ed) 152 { 153 tt.set(dd[x]); 154 x=anc[x][0]; 155 } 156 tt.set(dd[x]); 157 } 158 void jump2(int &x,int ed) 159 { 160 int x1=x; 161 while(x1!=1&&dep[rt[bl[x1]]]>=dep[ed]) x1=rt[bl[x1]]; 162 tt|=vv[nn[x]][nn[x1]]; 163 x=x1; 164 } 165 int main() 166 { 167 168 init(); 169 int i,a,b,a1,a2,t,lans=0,l; 170 scanf("%d%d%d",&n,&m,&F); 171 for(i=1;i<=n;i++) scanf("%d",&dd[i]); 172 for(i=1;i<n;i++) 173 { 174 scanf("%d%d",&a,&b); 175 e[a].pb(b);e[b].pb(a); 176 } 177 GBLOCK::work();LCA::dfs(1,0);PRE::work(); 178 while(m--) 179 { 180 scanf("%d",&t);tt.reset(); 181 for(i=1;i<=t;i++) 182 { 183 scanf("%d%d",&a,&b); 184 if(F) a^=lans,b^=lans; 185 l=lca(a,b); 186 if(a!=1&&dep[rt[bl[a]]]>=dep[l]) jump1(a,-1); 187 if(b!=1&&dep[rt[bl[b]]]>=dep[l]) jump1(b,-1); 188 jump2(a,l); 189 jump2(b,l); 190 jump1(a,l);jump1(b,l); 191 } 192 a1=tt.count(); 193 a2=tt._Find_first_zero(); 194 printf("%d %d\n",a1,a2); 195 lans=a1+a2; 196 } 197 return 0; 198 }
此方法相比直接分块然后处理边角,常数还是算小的,能够比bzoj2589https://www.cnblogs.com/hehe54321/p/9463519.html里面的做法快,但是还是过不去...
扫描二维码关注公众号,回复:
2801009 查看本文章