码迷,mamicode.com
首页 > 其他好文 > 详细

SDOI2018

时间:2020-07-24 21:52:20      阅读:74      评论:0      收藏:0      [点我收藏+]

标签:期望   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();
	}
}

旧试题
反回文串
荣誉称号

SDOI2018

标签:期望   std   关系   问题   相同   树上莫队   要求   pre   add   

原文地址:https://www.cnblogs.com/cszmc2004/p/13374123.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!