20191018+
前言
- 本场考试,感受颇深。
- 比如:语文是多么重要!
- 还有,一些情况下柿子不一定要化简,也可以化成更复杂但更有利于降低复杂度的柿子。
T1
- 树上主席树维护前驱,建出一棵新树,树上倍增即可。
- 时空复杂度$Theta(NlogN)$。
#include<cstdio> #define L tr[k].lc #define R tr[k].rc using namespace std; int const N=1e5+5; int n,q; int head[N],Next[N<<1],to[N<<1],t; int w[N]; int Log[N],dep[N],f[N][19],tot; int dfn[N],id[N]; struct node{ int lc,rc,maxx; }tr[N*50]; int root[N],ct; inline int read(){ int ss(0);char bb(getchar()); while(bb<48||bb>57)bb=getchar(); while(bb>=48&&bb<=57)ss=(ss<<1)+(ss<<3)+(bb^48),bb=getchar(); return ss; } inline int max(int x,int y){ return x>y?x:y; } inline void add(int x,int y){ to[++t]=y; Next[t]=head[x],head[x]=t; return ; } int ask(int l,int r,int x,int k){ if(!k)return 0; if(l>=x)return tr[k].maxx; int mid=l+r>>1; return x<=mid?max(ask(l,mid,x,L),ask(mid+1,r,x,R)):ask(mid+1,r,x,R); } inline int insert(int l,int r,int x,int y,int p){ int k=++ct,cnow=k,mid; tr[k].maxx=max(y,tr[p].maxx); do{ mid=l+r>>1; if(x<=mid)r=mid,R=tr[p].rc,p=tr[p].lc,k=L=++ct; else l=mid+1,L=tr[p].lc,p=tr[p].rc,k=R=++ct; tr[k].maxx=max(y,tr[p].maxx); }while(l^r); return cnow; } void dfs(int x,int y){ id[dfn[x]=++tot]=x; dep[tot]=dep[f[tot][0]=ask(1,N,w[x]+1,root[y])]+1; for(register int i=0,lt=Log[dep[tot]];i<lt;++i) f[tot][i+1]=f[f[tot][i]][i]; root[x]=insert(1,N,w[x],tot,root[y]); for(int i=head[x];i;i=Next[i]) if(to[i]^y)dfs(to[i],x); return ; } int main(){ //freopen("2.in","r",stdin); //freopen("1.out","w",stdout); n=read(),q=read(); Log[0]=-1; for(register int i=1;i<=n;++i)w[i]=read(),Log[i]=Log[i>>1]+1; for(register int i=1,ff,tt;i<n;++i) ff=read(),tt=read(),add(ff,tt),add(tt,ff); dfs(1,0); while(q--){ int x=read(),y=dfn[read()],gl=ask(1,N,read()+1,root[x]); if(gl<y){puts("0");continue;} int ans=1; for(register int i=Log[dep[gl]];~i;--i) if(f[gl][i]>=y)ans+=1<<i,gl=f[gl][i]; printf("%d ",ans); } return 0; }
T2
- 都说是语文题,但我读懂了,而且发现了竞赛图不是拓扑图就含有三元环的性质后还是不会……
- 正解是单步容斥。
- 首先总方案是$C_n^3$。
- 对于每个点,该点和任意两条出边所到达的点组不成三元环。
- 其实入边也是,但会重复。
- 设点i的出度为degree[i],未确定的边数为unlock[i]。
- 一条不确定的边成为出边的概率是$frac{1}{2}$。
- 则由任意两条确定的出边组成的方案是$C_{degree[i]}^2$。
- 由一条确定的出边和一条不确定的出边组成的方案是$frac{1}{2}degree[i]*unlock[i]$。
- 由两条不确定的出边组成的方案是$frac{1}{4}C_{unlock[i]}^2$。
- 都容斥掉即可。
- 时空复杂度$Theta(N+E)$。
#include<cstdio> #define ll long long using namespace std; int const N=1e5+5,M=1e6+5,mod=1e9+7; int n,e,du[N],w[N]; inline int read(){ int ss(0);char bb(getchar()); while(bb<48||bb>57)bb=getchar(); while(bb>=48&&bb<=57)ss=(ss<<1)+(ss<<3)+(bb^48),bb=getchar(); return ss; } inline ll power(ll x,int y){ ll as=1; for(;y;y>>=1,x=x*x%mod) if(y&1)as=as*x%mod; return as; } int main(){ //freopen("1.in","r",stdin); //freopen("1.out","w",stdout); n=read(),e=read(); for(register int i=1;i<=n;++i)w[i]=n-1; for(register int i=1,ff,tt;i<=e;++i)++du[read()],--w[read()]; long long ans=1ll*n*(n-1)*(n-2)/2/3; long long inv2=power(2,mod-2),inv4=power(4,mod-2); for(register int x=1;x<=n;++x){ ans-=(1ll*du[x]*(du[x]-1)>>1)+(1ll*du[x]*(w[x]-du[x])*inv2) +(1ll*(w[x]-du[x])*(w[x]-du[x]-1)>>1)*inv4; ans=(ans%mod+mod)%mod; } printf("%lld",ans); return 0; }