【NOIp2019模拟】题解

T1:

把每个颜色拿出来做一次线段树分治
离散化一下时间否则妥妥的T

有条边不选就是有个时间被删了又加上而已

#include<bits/stdc++.h>
using namespace std;
const int RLEN=1<<20|1;
inline char gc(){
	static char ibuf[RLEN],*ib,*ob;
	(ob==ib)&&(ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
	return (ob==ib)?EOF:*ib++;
}
inline int read(){
	char ch=gc();
	int res=0,f=1;
	while(!isdigit(ch))f^=ch=='-',ch=gc();
	while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=gc();
	return f?res:-res;
}
#define ll long long
#define re register
#define pii pair<int,int>
#define fi first
#define se second
#define pb push_back
#define pob pop_back
#define cs const
#define poly vector<int>
#define db double
#define bg begin
cs int mod=1004535809,G=3;
inline void chemx(int &a,int b){a<b?a=b:0;}
inline void chemn(int &a,int b){a>b?a=b:0;}
cs int N=100005,M=500005;
int n,m,k,qnum,tt;
map<int,int> mp;
inline int id(int x){
	return mp.count(x)?mp[x]:(mp[x]=++tt);
}
pii edge[M];
struct opt{
	int l,r;pii edge;
};
vector<opt>q1[M],q2[M];
vector<int>q[M];
int col[M],t1[M],t2[M],ans[M],ok[M];
namespace Set{
	int col[N],fa[N],siz[N];
	pii stk[N];int top;
	inline void init(){
		for(int i=1;i<=n;i++)fa[i]=i,siz[i]=1;
	}
	inline int find(int &x){
		int t=0;
		while(x!=fa[x])t^=col[x],x=fa[x];
		return t;
	}
	inline bool merge(int u,int v){
		int f1=find(u),f2=find(v);
		if(u==v)return f1!=f2;
		if(siz[u]<siz[v])swap(v,u);
		siz[u]+=siz[v],fa[v]=u,col[v]=f1^f2^1;
		stk[++top]=pii(u,v);
		return 1;
	}
	inline void getback(int pre){
		static int u,v;
		while(top>pre){
			u=stk[top].fi,v=stk[top].se;
			siz[u]-=siz[v],col[v]=0,fa[v]=v;
			top--;
		}
	}
}
int d[M*4],cnt,tim;
namespace Seg{
	int rt,lc[M<<2],rc[M<<2],tot,vis[M<<2],visq[M<<2];
	vector<pii> e[M<<2];
	#define mid ((l+r)>>1)
	inline void clear(){
		rt=tot=0;
	}
	inline void build(int &u,int l,int r){
		if(!u)u=++tot;
		e[u].clear();
		vis[u]=visq[u]=0;
		if(l==r)return;
		build(lc[u],l,mid);
		build(rc[u],mid+1,r);
	}
	inline void inserte(int u,int l,int r,int st,int des,pii p){
		if(vis[u]!=tim)vis[u]=tim,e[u].clear();
		if(st<=l&&r<=des){
			e[u].pb(p);return;
		}
		if(st<=mid)inserte(lc[u],l,mid,st,des,p);
		if(mid<des)inserte(rc[u],mid+1,r,st,des,p);
	}
	inline void insertq(int u,int l,int r,int p){
		visq[u]=1;
		if(l==r)return;
		if(p<=mid)insertq(lc[u],l,mid,p);
		else insertq(rc[u],mid+1,r,p);
	}
	inline void calc1(int u,int l,int r,int hav){
		if(vis[u]!=tim){
			if(hav)ans[l]++,ans[r+1]--;return;
		}
		int pre=Set::top,flag=0;
		for(pii &v:e[u]){
			if(!Set::merge(v.fi,v.se)){
				flag=1;break;
			}
		}
		if(!flag){
			if(l==r)ans[l]++,ans[r+1]--;
			else{
				calc1(lc[u],l,mid,hav||e[u].size());
				calc1(rc[u],mid+1,r,hav||e[u].size());
			}
		}
		Set::getback(pre);
	}
	inline void calc2(int u,int l,int r){
		if(!visq[u])return;
		int pre=Set::top,flag=0;
		for(pii &v:e[u]){
			if(!Set::merge(v.fi,v.se)){
				flag=1;break;
			}
		}
		if(!flag){
			if(l==r)ok[d[l]]=1;
			else{
				calc2(lc[u],l,mid);
				calc2(rc[u],mid+1,r);
			}
		}
		Set::getback(pre);
	}
}
using namespace Seg;
inline void solve1(int p){
	++tim;
	if(!q1[p].size())return;
	for(opt &x:q1[p]){
		inserte(1,1,qnum,x.l,x.r,x.edge);
	}
	calc1(1,1,qnum,0);
}
inline void solve2(int p){
	if(!q2[p].size()){
		for(int &x:q[p])ok[x]=1;
		return;
	}
	clear(),cnt=0;
	for(opt &v:q2[p])d[++cnt]=v.l,d[++cnt]=v.r;
	for(int &v:q[p])d[++cnt]=v;
	sort(d+1,d+cnt+1),cnt=unique(d+1,d+cnt+1)-d-1;
	build(rt,1,cnt);
	for(opt &x:q2[p]){
		int l=lower_bound(d+1,d+cnt+1,x.l)-d,
		r=lower_bound(d+1,d+cnt+1,x.r)-d;
		inserte(1,1,cnt,l,r,x.edge);
	}
	for(int &x:q[p]){
		int pos=lower_bound(d+1,d+cnt+1,x)-d;
		insertq(1,1,cnt,pos);
	}
	calc2(1,1,cnt);
}
int main(){
	n=read(),m=read(),k=read();
	Set::init();
	for(int i=1;i<=m;i++){
		col[i]=id(read());
		edge[i].fi=read(),edge[i].se=read();
	}
	for(int i=1;i<=k;i++){
		int c=read();
		if(c==0){
			qnum++;
			int qcol=id(read()),bane=read();
			q[qcol].pb(qnum);
			if(bane&&col[bane]==qcol){
				if(t2[bane]<qnum-1)
				q2[qcol].pb(opt{t2[bane]+1,qnum-1,edge[bane]});
				t2[bane]=qnum;
			}
		}
		else{
			int d=id(read());
			if(d==col[c])continue;
			if(t1[c]<qnum)
				q1[col[c]].pb(opt{t1[c]+1,qnum,edge[c]}),t1[c]=qnum;
			if(t2[c]<qnum)
				q2[col[c]].pb(opt{t2[c]+1,qnum,edge[c]}),t2[c]=qnum;
			col[c]=d;
		}
	}
	for(int i=1;i<=m;i++){
		if(t1[i]<qnum)q1[col[i]].pb(opt{t1[i]+1,qnum,edge[i]});
		if(t2[i]<qnum)q2[col[i]].pb(opt{t2[i]+1,qnum,edge[i]});
	}
	clear(),build(rt,1,qnum);
	for(int i=1;i<=tt;i++)solve1(i);
	for(int i=1;i<=tt;i++)solve2(i);
	for(int i=1;i<=qnum;i++){
		cout<<(ok[i]?"YES":"NO")<<'\n';
		cout<<(ans[i]+=ans[i-1])<<'\n';
	}
}

T2:

不会
zxyzxynlog2nnlog^2nnlognnlogn纠结半天后才知道前面还有一个nnn\sqrt n

T3:

其实很水
自己子树自己点分治nttntt就完了
把环上子树俩俩拿出来算贡献
分三种情况
环没断,左边断了,右边断了
分别算一下贡献

#include<bits/stdc++.h>
using namespace std;
const int RLEN=1<<20|1;
inline char gc(){
	static char ibuf[RLEN],*ib,*ob;
	(ob==ib)&&(ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
	return (ob==ib)?EOF:*ib++;
}
#define gc getchar
inline int read(){
	char ch=gc();
	int res=0,f=1;
	while(!isdigit(ch))f^=ch=='-',ch=gc();
	while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=gc();
	return f?res:-res;
}
#define ll long long
#define re register
#define pii pair<int,int>
#define fi first
#define se second
#define pb push_back
#define pob pop_back
#define cs const
#define poly vector<int>
#define db double
#define bg begin
cs int mod=1004535809,G=3;
inline int add(int a,int b){return a+b>=mod?a+b-mod:a+b;}
inline void Add(int &a,int b){a=add(a,b);}
inline int dec(int a,int b){return a>=b?a-b:a-b+mod;}
inline void Dec(int &a,int b){a=dec(a,b);}
inline int mul(int a,int b){return 1ll*a*b>=mod?1ll*a*b%mod:a*b;}
inline void Mul(int &a,int b){a=mul(a,b);}
inline int ksm(int a,int b,int res=1){for(;b;b>>=1,a=mul(a,a))(b&1)?(res=mul(res,a)):0;return res;}
inline void chemx(int &a,int b){a<b?a=b:0;}
inline void chemn(int &a,int b){a>b?a=b:0;}
cs int N=100005,C=20;
int rev[N<<2]; 
poly w[C+1];
inline void init_rev(int lim){
	for(int i=0;i<lim;i++)rev[i]=(rev[i>>1]>>1)|((i&1)*(lim>>1));
}
inline void init_w(){
	for(int i=1;i<=C;i++)w[i].resize(1<<(i-1));
	int wn=ksm(G,(mod-1)/(1<<C));
	w[C][0]=1;
	for(int i=1;i<(1<<(C-1));i++)w[C][i]=mul(w[C][i-1],wn);
	for(int i=C-1;i;i--)
	for(int j=0;j<(1<<(i-1));j++)
	w[i][j]=w[i+1][j<<1];
} 
inline void ntt(poly &f,int lim,int kd){
	for(int i=0;i<lim;i++)if(i>rev[i])swap(f[i],f[rev[i]]);
	for(int mid=1,l=1,a0,a1;mid<lim;mid<<=1,l++)
	for(int i=0;i<lim;i+=(mid<<1))
	for(int j=0;j<mid;j++)
	a0=f[i+j],a1=mul(f[i+j+mid],w[l][j]),f[i+j]=add(a0,a1),f[i+j+mid]=dec(a0,a1);
	if(kd==-1){
		reverse(f.bg()+1,f.bg()+lim);
		for(int i=0,inv=ksm(lim,mod-2);i<lim;i++)Mul(f[i],inv);
	}
}
inline poly operator *(poly a,poly b){
	int deg=a.size()+b.size()-1,lim=1;
	if(deg<=128){
		poly c(deg,0);
		for(int i=0;i<a.size();i++)
		for(int j=0;j<b.size();j++)
		Add(c[i+j],mul(a[i],b[j]));
		return c;
	}
	while(lim<deg)lim<<=1;
	init_rev(lim),a.resize(lim),b.resize(lim);
	ntt(a,lim,1),ntt(b,lim,1);
	for(int i=0;i<lim;i++)Mul(a[i],b[i]);
	ntt(a,lim,-1),a.resize(deg);
	return a;
}
vector<int> e[N];
int val[N],vis[N],dis[N],siz[N],son[N];
int n,m,tot,dfn[N],tim,pre[N],isc[N],cir[N];
inline void findc(int u){
	dfn[u]=++tim;
	for(int &v:e[u]){
		if(v==pre[u])continue;
		if(!dfn[v])pre[v]=u,findc(v);
		else if(dfn[v]<dfn[u]){
			cir[++tot]=v,vis[v]=1;
			for(int x=u;x!=v;x=pre[x])cir[++tot]=x,vis[x]=1;
			return;
		}
	}
}
int rt,maxn;
void getrt(int u,int fa){
	siz[u]=1,son[u]=0;
	for(int &v:e[u]){
		if(v==fa||vis[v])continue;
		getrt(v,u),siz[u]+=siz[v];
		chemx(son[u],siz[v]);
	}
	chemx(son[u],maxn-son[u]);
	if(son[u]<son[rt])rt=u;
}
double ans;
inline void getdis(poly &f,int u,int fa,int dep){
	if(((int)f.size())<=dep+1)f.resize(dep+1);
	f[dep]++;
	siz[u]=1;
	for(int &v:e[u]){
		if(v==fa||vis[v])continue;
		getdis(f,v,u,dep+1);
		siz[u]+=siz[v];
	}
}
inline void calc_ans(poly now,int mor,int coef){
	for(int i=0;i<now.size();i++)
	ans+=1.0*coef*now[i]/(i+mor);
}
void getans(int u,int mor,int coef){
	poly res;
	getdis(res,u,0,0);
	res=res*res;
	calc_ans(res,mor,coef);
}
void solve(int u){
	vis[u]=1;
	getans(u,1,1);
	for(int &v:e[u]){
		if(vis[v])continue;
		getans(v,3,-1);
		maxn=siz[v];
		getrt(v,rt=0);
		solve(rt);
	}
}
inline void calc(int u){
	maxn=siz[u];
	getrt(u,rt=0);
	solve(rt);
}
poly f[N]; 
int main(){
	maxn=son[0]=n=read();init_w();
	for(int i=1;i<=n;i++){
		int u=read(),v=read();
		e[u].pb(v),e[v].pb(u);
	}
	findc(1);double pp=0;
	for(int i=1;i<=tot;i++){
		vis[cir[i]]=0;
		getdis(f[i],cir[i],0,0);
		calc(cir[i]);
		vis[cir[i]]=1;
	}
	double tmp=ans;ans=0;
	for(int i=1;i<=tot;i++)
	for(int j=i+1;j<=tot;j++){
		int a=j-i-1,b=tot-j+i-1;
		poly res=f[i]*f[j];
		calc_ans(res,a+2,1);
		calc_ans(res,b+2,1);
		calc_ans(res,a+b+2,-1);
	}
	printf("%.6lf",(tmp+ans*2)/n);
	exit(0);
}
posted @ 2019-08-24 13:20  Stargazer_cykoi  阅读(71)  评论(0编辑  收藏  举报