标签:期望 std 关系 问题 相同 树上莫队 要求 pre add
战略游戏
题目要求求删除后能使一些点不连通的点的个数。
删点可以想到点双树。
建出原图的点双树。
一条路径x,y上的点如果被删除,则x,y不能互相到达。
如果把圆点的权值设为1,方点的设为0,则答案就是虚树的点权和。
实际上,不用把虚树建出来。可以使用一个经典结论。
如果把一个点的权值放在父亲边上,则链的并的长度就是答案。
把点按照dfs序排序,最后添加dfs序最小的点。
则相邻两个点的距离加起来/2就是答案。
物理实验
原题识别
比较毒瘤的二维数点。
实际上不用计算期望,乘以对应的数后就变成了计数。
sub1直接树上莫队。
这和正解没有任何关系。要解决该题,需要发现如下随机性质:
1.颜色数期望\(O(1)\)
2.两个点到lca的距离的min值期望log
先考虑第一问。
假设询问是(x,y),且x->lca的距离<=y->lca的距离。
使用可持久化线段树计算y->lca的点的颜色个数。
枚举x到lca的所有点,计算这个点的颜色是否在y->lca的路径上出现。
此部分时间复杂度期望\(O(log_2n)\)。
链的做法是树的做法的简化版。
第二问可以分每个节点计算贡献。
根据数颜色经典套路,设\(p_i\)表示i节点前面第一个颜色相同的位置。
如果一个点\(A< i\leq B, p_i\leq A\),贡献\((A-p_i)(B-i+1)\),
如果一个点\(1\leq i\leq A,x\leq y\),贡献\((i-p_i)(B-i+1)\)
如果一个点\(1\leq i\leq A,x\geq y\),贡献\((i-p_i)(A-i+1)\)
第二,三个贡献会多算\(x=y\),减掉\(A\)即可。
设\(f\)是x,y的lca
拆第一个贡献的式子。
\(\sum_{i=A+1,p_i\leq A}^B (A-p_i)(B-i+1)\\=A(B+1)\sum 1-(B+1)\sum p_i-A\sum i+\sum p_ii\)
使用可持久化线段树维护\(\sum 1,\sum p_i,\sum i,\sum p_ii\)
拆第2,3个贡献的式子。
\(\sum_{i=1}^A (i-p_i)(B-i+1)+\sum_{i=1}^A (i-p_i)(A-i+1)\\=(A+B+2)\sum (i-p_i)-2\sum i(i-p_i)\)
使用前缀和维护\(\sum_{i=1}^A (i-p_i)(B-i+1)+\sum_{i=1}^A (i-p_i)(A-i+1)\\=(A+B+2)\sum (i-p_i)-2\sum i(i-p_i)\)
拓展到树上,前缀和/可持久化线段树从父亲转移到现在的点。
把问题划分成3个。
1.\(x\in [1,f),y\in [1,B]\),和链上的情况一样。
2.\(x\in [f,A],y\in [1,f]\)
用\(x\in [1,A],y\in [1,f)\)的贡献减去\(x\in [1,f),y\in [1,f)\)的贡献。
\(x\in [1,A],y\in [1,f)\)和链上的情况一样。
\(x\in [1,f),y\in [1,f)\)的贡献是\(\sum_{i=1}^{f-1} (2(i-p_i)(f-i)-1)\)
3.\(x\in [f,A],y\in [f,B]\)
先计算\(i\in [f,B]\)的贡献,是
\(\sum_{i=f,p_i< f}^B (B-i+1)(A-f+1)\)
再计算\(i\in (f,A]\)的贡献。
首先i要满足\(p_i\leq f\)。设\(j\)为\([f,B]\)中第一个和它颜色相同的点(若没有,则j=B+1)。那么贡献为\((A?i+1)(j?f)\)。
代码很难写。
#include<bits/stdc++.h>
using namespace std;
#define N 200010
#define cv(x) memset(x,0,sizeof(x))
unsigned int sa, sb, sc;
unsigned int rng61(){
sa ^= sa << 16;
sa ^= sa >> 5;
sa ^= sa << 1;
unsigned int t = sa;
sa = sb;
sb = sc;
sc ^= t ^ sa;
return sc;
}
#define int long long
struct no{
int a,b,c,d;
}b[N*20];
no operator+(no x,no y){
return (no){x.a+y.a,x.b+y.b,x.c+y.c,x.d+y.d};
}
no operator-(no x,no y){
return (no){x.a-y.a,x.b-y.b,x.c-y.c,x.d-y.d};
}
int n,s,f[N],rt[N],lc[N*20],rc[N*20],h[N],v[N],nxt[N],ec,a[N],m,g[N][20],d[N],ct,p[N],bc[N],cc,in[N],ou[N],lg[N],s1[N],s2[N];
vector<int>cl[N];
void add(int x,int y){v[++ec]=y;nxt[ec]=h[x];h[x]=ec;}
void adj(int x,int y){add(x,y);add(y,x);}
int gd(int x,int y){
return d[x]<d[y]?x:y;
}
void ins(int &o,int p,int l,int r,int x,no y){
o=++ct;
b[o]=b[p]+y;
if(l==r)return;
int md=(l+r)/2;
if(x<=md){
rc[o]=rc[p];
ins(lc[o],lc[p],l,md,x,y);
}
else{
lc[o]=lc[p];
ins(rc[o],rc[p],md+1,r,x,y);
}
}
no qu(int o,int p,int l,int r,int x,int y){
if(r<x||y<l||x>y)
return(no){0,0,0,0};
if(x<=l&&r<=y)
return b[o]-b[p];
int md=(l+r)/2;
return qu(lc[o],lc[p],l,md,x,y)+qu(rc[o],rc[p],md+1,r,x,y);
}
void dfs(int x,int fa){
f[x]=fa;
d[x]=d[fa]+1;
g[x][0]=fa;
cc++;
in[x]=cc;
p[x]=bc[a[x]];
int lc=bc[a[x]];
bc[a[x]]=x;
s1[x]=s1[fa]+d[x]-d[p[x]];
s2[x]=s2[fa]+d[x]*(d[x]-d[p[x]]);
ins(rt[x],rt[f[x]],0,n,d[p[x]],(no){1,d[p[x]],d[x],d[p[x]]*d[x]});
for(int i=h[x];i;i=nxt[i])
if(v[i]!=fa)
dfs(v[i],x);
ou[x]=cc;
bc[a[x]]=lc;
}
int lca(int x,int y){
if(d[x]>d[y])swap(x,y);
for(int i=19;~i;i--)
if(d[g[y][i]]>=d[x])
y=g[y][i];
if(x==y)return x;
for(int i=19;~i;i--)
if(g[x][i]!=g[y][i])
x=g[x][i],y=g[y][i];
return g[x][0];
}
int di(int x,int y){
return d[x]+d[y]-2*d[lca(x,y)];
}
int pd(int x,int y,int z){
return in[x]<=in[z]&&in[z]<=ou[x]&&in[z]<=in[y]&&in[y]<=ou[z];
}
int qc(int x,int y){
if(d[x]>d[y])swap(x,y);
if(!x||!y)return 0;
int va=s1[x]*(d[x]+d[y]+2)-2*s2[x];
no v=qu(rt[y],rt[x],0,n,0,d[x]);
va+=d[x]*(d[y]+1)*v.a;
va-=(d[y]+1)*v.b;
va-=d[x]*v.c;
va+=v.d;
va-=d[x];
return va;
}
int q2(int x,int y){
int lc=lca(x,y),va=0;
if(di(x,lc)>di(y,lc))
swap(x,y);
va+=qc(f[lc],y);
int vv=qc(x,f[lc]);
vv-=-d[lc]+1+2*s1[f[lc]]*d[lc]-2*s2[f[lc]];
va+=vv;
no vg=qu(rt[y],rt[f[lc]],0,n,0,d[f[lc]]);
va+=vg.a*(d[x]-d[lc]+1+d[x]*d[y]-d[y]*d[lc]+d[y]);
va+=(d[lc]-1-d[x])*vg.c;
for(int i=x;i!=lc;i=f[i])
if(d[p[i]]<=d[lc]){
int j=d[y]+1;
for(int k:cl[a[i]])
if(pd(lc,y,k))
if(j>d[k])j=d[k];
va+=(d[x]-d[i]+1)*(j-d[lc]);
}
return va;
}
int q1(int x,int y){
int lc=lca(x,y),va;
if(di(x,lc)>di(y,lc))
swap(x,y);
va=qu(rt[y],rt[f[lc]],0,n,0,d[f[lc]]).a;
for(int i=x;i!=lc;i=f[i]){
int ok=1;
for(int j:cl[a[i]])
if(pd(lc,y,j))
ok=0;
va+=ok;
}
return va;
}
signed main(){
for(int i=2;i<N;i++)
lg[i]=lg[i>>1]+1;
int t;
cin>>t;
while(t--){
cv(f);
cv(rt);
for(int i=1;i<=ct;i++)
lc[i]=rc[i]=b[i].a=b[i].b=b[i].c=b[i].d=0;
cv(h);
cv(v);
cv(nxt);
ec=ct=cc=0;
cv(a);
cv(g);
cv(d);
cv(p);
cv(bc);
cv(in);
cv(ou);
cv(s1);
cv(s2);
cin>>n>>s>>sa>>sb>>sc;
for(int i = 2; i <= s; i++)
adj(i - 1, i);
for(int i = s + 1; i <= n; i++)
adj(rng61() % (i - 1) + 1, i);
int mxc=0;
for(int i = 1; i <= n; i++){
a[i] = rng61() % n + 1;
cl[a[i]].push_back(i);
mxc=max(mxc,a[i]);
}
cin>>m;
dfs(1,0);
g[1][0]=1;
for(int i=1;i<20;i++)
for(int j=1;j<=n;j++)
g[j][i]=g[g[j][i-1]][i-1];
while(m--){
if(!t){
t++;
t--;
}
int op,x,y;
cin>>op>>x>>y;
if(op==1)
cout<<q1(x,y)<<‘\n‘;
else cout<<q2(x,y)<<‘\n‘;
}
for(int i=1;i<=mxc;i++)
cl[i].clear();
}
}
旧试题
反回文串
荣誉称号
标签:期望 std 关系 问题 相同 树上莫队 要求 pre add
原文地址:https://www.cnblogs.com/cszmc2004/p/13374123.html