【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:
不会
在和纠结半天后才知道前面还有一个
T3:
其实很水
自己子树自己点分治就完了
把环上子树俩俩拿出来算贡献
分三种情况
环没断,左边断了,右边断了
分别算一下贡献
#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);
}