模拟赛
单 \(log\) 双 \(log\) 不如三 \(log\)。
T1 一般图最小匹配
简单 dp,水。\(O(n^2)\)
其实也是可反悔贪心的板子,可以 \(O(n\log(n))\) 做。
考虑排序后求差分数组,就变成不能选相邻的。然后就是可反悔贪心板子。
用双向链表(记录前驱后继)维护,然后放进堆里。
板
dp
#include<bits/stdc++.h>
using namespace std;
#define ab(x) ((x>=0)?(x):(-x))
#define mi(x,y) ((x>y)?(y):(x))
#define LL long long
const int N = 5005;
int n,m;
LL f[2][N][2],a[N];int main()
{freopen("match.in","r",stdin);freopen("match.out","w",stdout);scanf("%d%d",&n,&m);for(int i=1;i<=n;i++) scanf("%lld",&a[i]);sort(a+1,a+1+n);memset(f,0x3f,sizeof(f));f[0][1][1]=ab(a[2]-a[1]); f[0][0][0]=0;for(int i=3;i<=n;i++){f[i&1][0][0]=0;for(int j=1;j<=i>>1;j++){f[i&1][j][1]=f[(i-1)&1][j-1][0]+ab(a[i]-a[i-1]);f[i&1][j][0]=mi(f[(i-1)&1][j][0],f[(i-1)&1][j][1]);}}printf("%lld\n",mi(f[n&1][m][0],f[n&1][m][1]));return 0;
}
贪心
#include<bits/stdc++.h>
using namespace std;
const int N = 5e3+5;
int n,m,pre[N],nxt[N];
long long ans,b[N],a[N];
struct A
{int id; long long d;bool operator < (const A &x) const{return d>x.d;}
};
bool vs[N];
priority_queue<A> q;
int main()
{freopen("match.in","r",stdin);freopen("match.out","w",stdout);scanf("%d%d",&n,&m);for(int i=1;i<=n;i++) scanf("%lld",&a[i]);sort(a+1,a+1+n);for(int i=1;i<n;i++) b[i]=a[i+1]-a[i],q.push({i,b[i]}),pre[i]=i-1,nxt[i]=i+1;b[0]=b[n]=1e9;while(m){while(vs[q.top().id]) q.pop();int u=q.top().id; long long d=q.top().d; q.pop();m--; vs[pre[u]]=vs[nxt[u]]=1; b[u]=b[pre[u]]+b[nxt[u]]-b[u];q.push({u,b[u]});pre[u]=pre[pre[u]],nxt[u]=nxt[nxt[u]],nxt[pre[u]]=u,pre[nxt[u]]=u;ans+=d;}printf("%lld\n",ans);return 0;
}
T2 重定向
大力分讨,不停贪心。
细节处理挂 \(30 pts\)。
code
#include<bits/stdc++.h>
using namespace std;
const int N = 2e5+5;
int n,T;
int l,cnt,ans[N],a[N],tot;
bool vs[N];int main()
{freopen("repeat.in","r",stdin);freopen("repeat.out","w",stdout);scanf("%d",&T);while(T--){cnt=tot=0;set<int> h,p;memset(vs,0,sizeof(vs));scanf("%d",&n);for(int i=1;i<=n;i++){scanf("%d",&a[i]); vs[a[i]]=1; if(a[i]!=0) h.insert(a[i]);}p.insert(100000000);for(int i=1;i<=n;i++) if(!vs[i]) p.insert(i);bool fl=0; int _1=0;for(int i=1;i<=n;i++){if(a[i]!=0&&a[i]==_1) continue;if(a[i]!=0) h.erase(a[i]);if(i+1<=n&&fl==0){if(a[i]==0){if(a[i+1]!=0){if(!_1&&!h.empty()&&(*h.begin()<a[i+1])&&(*h.begin()<*p.begin())){_1=(*h.begin());ans[++tot]=_1;fl=1; continue;} else if(a[i+1]<*p.begin()){fl=1; continue;} else{ans[++tot]=*p.begin(); p.erase(p.begin()); continue;}}else {if(!_1&&!h.empty()&&*p.begin()>*h.begin()){_1=(*h.begin());ans[++tot]=_1;fl=1; continue; }else{ans[++tot]=*p.begin(); p.erase(p.begin()); continue;}}}else{if(a[i+1]!=0&&a[i+1]<a[i]) {p.insert(a[i]);fl=1; continue;}else if(a[i+1]==0&&*p.begin()<a[i]){p.insert(a[i]);fl=1; continue;}else{ans[++tot]=a[i]; continue;} }}else if(fl==0){continue;}else{if(a[i]==0) ans[++tot]=*p.begin(), p.erase(p.begin());else ans[++tot]=a[i];}}for(int i=1;i<=tot;i++) printf("%d ",ans[i]); putchar('\n');}return 0;
}
T3 斯坦纳树
转化题意,发现如果有重边那就是不合法的,考虑什么时候会有重边。
加入的点会形成一个最小连通块,这就是我们要判断的区域。
我们可以将所有点分成三类:
-
已经加入的。
-
未被加入但在连通块中的。
-
不在连通块中的。
考虑一个不在连通块中的点想接入连通块,那么一定会与连通块有一个交点。
假如上图中三号点想加入连通块,那么这个交点就是二号点。
如果二号点已经被加入的话,那么三号点不会造成影响,否则一定会有重边。
所以我们就是想找到这个交点并判断它是否加入。
赛时唐氏做法,线段树维护并查集,每次区间推平维护连通块,单点查询是否是交点,是否选过。
好处就是信息全在线段树里,复杂度能多一个 \(log\) 和大常熟。
最后 \(O(qlog^3(n))\) 的复杂度(很松很松)过了(\(O(qlog(n))\) 和 \(O(qlog^2(n))\) 没过)。
code
#include<bits/stdc++.h>
using namespace std;
const int N =3e5+5;
int n,a[N];
int head[N],tot,xx[N],yy[N],zz[N];
struct E {int u,v,w;} e[N<<1];
inline void add(int u,int v,int w) {e[++tot]={head[u],v,w}; head[u]=tot;}
bool fl=1;
int b[N];
inline int find(int x) {return x==b[x]?(x):(b[x]=find(b[x]));}
int sz[N],fa[N][30],dis[N],son[N],dfn[N],dep[N],rk[N],top[N],cnt;void dfs1(int u,int f)
{sz[u]=1; fa[u][0]=f; son[u]=-1; dep[u]=dep[f]+1;for(int i=1;i<=20;i++) fa[u][i]=fa[fa[u][i-1]][i-1];for(int i=head[u];i;i=e[i].u){int v=e[i].v; if(v==f) continue; dis[v]=dis[u]+e[i].w;dfs1(v,u); sz[u]+=sz[v];if(son[u]==-1||sz[son[u]]<sz[v]) son[u]=v;}
}
void dfs2(int u,int t)
{top[u]=t; dfn[u]=++cnt; rk[cnt]=u;// printf("%d %d\n",u,dfn[u]);if(son[u]==-1) return ;dfs2(son[u],t);for(int i=head[u];i;i=e[i].u){int v=e[i].v; if(v==fa[u][0]||v==son[u]) continue;dfs2(v,v);}
}
namespace SEG
{struct T{int l,r,cnt; bool xu,yo,za,lz;} tr[N<<2];inline void pushup(int k) {tr[k].cnt=tr[k<<1].cnt+tr[k<<1|1].cnt;}inline void pushdown(int k){if(tr[k].lz){tr[k].lz=0;tr[k<<1].lz=1; tr[k<<1].za=1;tr[k<<1|1].lz=1; tr[k<<1|1].za=1;}}void bui(int k,int l,int r){tr[k].l=l; tr[k].r=r;if(l>=r) return ; int mid=l+r>>1;bui(k<<1,l,mid); bui(k<<1|1,mid+1,r);}void mdf(int k,int p,int tp){if(tr[k].l==tr[k].r){if(tp==0)//yo{if(!tr[k].yo){tr[k].cnt-=tr[k].xu; tr[k].yo=1;} }else//xu{if(!tr[k].xu&&!tr[k].yo){tr[k].cnt++; tr[k].xu=1;// printf("*****\n");} }return;}pushdown(k);int mid=tr[k].l+tr[k].r>>1;if(p<=mid) mdf(k<<1,p,tp);else mdf(k<<1|1,p,tp);pushup(k);}void qmdf(int k,int L,int R){if(tr[k].l>=L&&tr[k].r<=R){tr[k].za=1; tr[k].lz=1; return;}pushdown(k);int mid=tr[k].l+tr[k].r>>1;if(L<=mid) qmdf(k<<1,L,R);if(R>mid) qmdf(k<<1|1,L,R);pushup(k);}bool que(int k,int p){if(tr[k].l==tr[k].r) return tr[k].za;pushdown(k);int mid=tr[k].l+tr[k].r>>1;if(p<=mid) return que(k<<1,p);else return que(k<<1|1,p);}
} using namespace SEG;void mdfpath(int x,int y)
{while(top[x]!=top[y]){if(dep[top[x]]<dep[top[y]]) swap(x,y);qmdf(1,dfn[top[x]],dfn[x]);x=fa[top[x]][0];}if(dfn[x]>dfn[y]) swap(x,y);qmdf(1,dfn[x],dfn[y]);return;
}void change(int x)
{int tmp=x;mdf(1,dfn[x],0);if(que(1,dfn[x])) return;for(int i=20;i>=0;i--){if(!fa[x][i]) continue;if(que(1,dfn[fa[x][i]])) continue;else x=fa[x][i];}mdf(1,dfn[fa[x][0]],1);mdfpath(fa[x][0],tmp);
}int main()
{freopen("tree.in","r",stdin);freopen("tree.out","w",stdout);scanf("%d",&n);for(int i=1;i<=n;i++) b[i]=i;for(int i=1;i<n;i++){int x,y,z; scanf("%d%d%d",&x,&y,&z);x=find(x); y=find(y);if(z==0) b[x]=y; xx[i]=x; yy[i]=y; zz[i]=z;}for(int i=1;i<n;i++){if(zz[i]!=0) {int x=find(xx[i]),y=find(yy[i]);add(x,y,zz[i]); add(y,x,zz[i]);}}for(int i=1;i<=n;i++) scanf("%d",&a[i]);dfs1(find(a[1]),0);dfs2(find(a[1]),find(a[1]));bui(1,1,n);int v=dfn[find(a[1])];mdf(1,v,0); qmdf(1,v,v); printf("1");for(int i=2;i<=n;i++){v=find(a[i]); change(v);if(tr[1].cnt==0) printf("1");else printf("0");}return 0;
}
T4 直径
咕咕咕