• 【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")<<'
    ';
    		cout<<(ans[i]+=ans[i-1])<<'
    ';
    	}
    }
    

    T2:

    不会
    zxyzxynlog2nnlog^2nnlognnlogn纠结半天后才知道前面还有一个nnnsqrt 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);
    }
    
  • 相关阅读:
    Python学习之列表
    Python学习笔记
    Linux基础命令总结
    CentOS6.6安装mysql-5.7.25二进制安装包简易教程
    执行 cobbler get-loaders报错
    windows下 Qt 安装 taglib 获取媒体信息windows
    Qt dropEvent和dragEnterEvent问题
    Qt---去掉标题栏后,最大化应用程序窗口时,窗口遮住了任务栏的问题
    Qt 单击任务栏图标实现最小化
    Qt 无边框窗口的两种实现
  • 原文地址:https://www.cnblogs.com/stargazer-cyk/p/12328629.html
Copyright © 2020-2023  润新知