省队集训Round2 DAY3
2017-08-20 11:17
344 查看
T1
题解
用splay维护权值有序。每次加入一个人,贪心的选出前i-1个人中要求最小的vi−1,判断能否满足,如果能满足就把这vi−1个人的权值-1,剩下的人不需要他们的支持,那么都赋值成0,并且把这些点移动到平衡树中0所在的位置;如果不能满足就直接在平衡树中加入一个-1.代码
#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #include<cstring> #define N 2000003 #define LL long long using namespace std; const LL inf=1e18; int ch [3],fa ,root,sz; int n; LL k,val ,sum ,delta ,cover ,size ; int get(int x) { return ch[fa[x]][1]==x; } void change(int now,LL v) { if (!now) return; val[now]+=v; sum[now]+=size[now]*v; if (cover[now]!=-inf) cover[now]+=v; else delta[now]+=v; } void change1(int now,LL v) { delta[now]=0; cover[now]=v; val[now]=v; sum[now]=v*size[now]; } void pushdown(int now) { if (delta[now]) { change(ch[now][0],delta[now]); change(ch[now][1],delta[now]); delta[now]=0; } if (cover[now]!=-inf) { change1(ch[now][0],cover[now]); change1(ch[now][1],cover[now]); cover[now]=-inf; } } void update(int now) { int l=ch[now][0]; int r=ch[now][1]; sum[now]=val[now]; size[now]=1; if (l) sum[now]+=sum[l],size[now]+=size[l]; if (r) sum[now]+=sum[r],size[now]+=size[r]; } void rotate(int x) { int y=fa[x]; int z=fa[y]; int which=get(x); pushdown(y); pushdown(x); ch[y][which]=ch[x][which^1]; fa[ch[x][which^1]]=y; ch[x][which^1]=y; fa[y]=x; fa[x]=z; if (z) ch[z][ch[z][1]==y]=x; update(y); update(x); } void splay(int x,int tar) { for (int f;(f=fa[x])!=tar;rotate(x)) if (fa[f]!=tar) rotate(get(x)==get(f)?f:x); if (!tar) root=x; } void insert(LL x) { int now=root; while (true) { pushdown(now); int f=now; now=ch[now][x>val[now]]; if (!now) { ++sz; sum[sz]=val[sz]=x; size[sz]=1; ch[f][x>val[f]]=sz; fa[sz]=f; cover[sz]=-inf; update(f); splay(f,0); return; } } } int find(int x) { int now=root; while (true) { pushdown(now); if (size[ch[now][0]]>=x) now=ch[now][0]; else { x-=size[ch[now][0]]; if (x==1) return now; x--; now=ch[now][1]; } } } int main() { freopen("yi.in","r",stdin); freopen("yi.out","w",stdout); scanf("%d%lld",&n,&k); root=1; sz=2; fa[2]=1; ch[1][1]=2; cover[1]=cover[2]=-inf; val[1]=-inf; sum[1]=0; val[2]=sum[2]=inf; size[1]=2; size[2]=1; for (int i=1;i<=n;i++) { int x; scanf("%d",&x); if (size[root]-2<x-1){ insert(-1); printf("-1\n"); continue; } int aa=find(1); int bb=find(x+1); splay(aa,0); splay(bb,aa); int t=ch[ch[root][1]][0]; if (sum[t]+x-1>k) { insert(-1); printf("-1\n"); continue; } if (t) { val[t]++; sum[t]+=size[t]; if (cover[t]!=-inf) cover[t]++; else delta[t]++; } LL v=k-sum[t]; aa=find(x); bb=find(size[root]); splay(aa,0); splay(bb,aa); t=ch[ch[root][1]][0]; if (t) { change1(t,0); ch[ch[root][1]][0]=0; fa[t]=0; update(ch[root][1]); update(root); aa=find(1); bb=find(2); splay(aa,0); splay(bb,aa); ch[ch[root][1]][0]=t; fa[t]=ch[root][1]; update(ch[root][1]); update(root); } insert(v); printf("%lld\n",v); } }
T3
题解
要求每一个时间每条边只能有一个人经过,每个人在到达终点前的任意时刻都不能停止。那么我们可以二分一个最晚的时间mid,然后建mid层结点,每条有向边x->y从i层的x结点连向i+1层的y结点,容量为1。然后跑最大流如果最后满流,那么说明mid可行,继续减小二分的范围
代码
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<cmath> #include<queue> #define N 3000003 #define inf 1000000000 using namespace std; int n,m,k,tot; int point ,nxt ,remain ,v ,cur ,last ,deep ,num ; int x[20000],y[20000]; void add(int x,int y,int z) { tot++; nxt[tot]=point[x]; point[x]=tot; v[tot]=y; remain[tot]=z; tot++; nxt[tot]=point[y]; point[y]=tot; v[tot]=x; remain[tot]=0; //cout<<x<<" "<<y<<" "<<z<<endl; } int addflow(int s,int t) { int ans=inf; int now=t; while (now!=s) { ans=min(ans,remain[last[now]]); now=v[last[now]^1]; } now=t; while (now!=s) { remain[last[now]]-=ans; remain[last[now]^1]+=ans; now=v[last[now]^1]; } return ans; } void bfs(int s,int t) { for (int i=1;i<=t;i++) deep[i]=t; queue<int> p; p.push(t); deep[t]=0; while (!p.empty()){ int now=p.front(); p.pop(); for (int i=point[now];i!=-1;i=nxt[i]) if (deep[v[i]]==t&&remain[i^1]) deep[v[i]]=deep[now]+1,p.push(v[i]); } } int isap(int s,int t) { int ans=0; int now=s; bfs(s,t); for (int i=1;i<=t;i++) num[deep[i]]++; for (int i=1;i<=t;i++) cur[i]=point[i]; while (deep[s]<t){ if (now==t) { ans+=addflow(s,t); now=s; } bool pd=false; for (int i=cur[now];i!=-1;i=nxt[i]) if (remain[i]&&deep[now]==deep[v[i]]+1) { cur[now]=i; last[v[i]]=i; pd=true; now=v[i]; break; } if (!pd) { int minn=t+1; for (int i=point[now];i!=-1;i=nxt[i]) if (remain[i]) minn=min(minn,deep[v[i]]); if (!--num[deep[now]]) break; num[deep[now]=minn+1]++; cur[now]=point[now]; if (now!=s) now=v[last[now]^1]; } } return ans; } bool check(int mid) { tot=-1; int S=n*mid+1; int T=n*mid+2; for (int i=1;i<=T;i++) num[i]=0; for (int i=1;i<=T;i++) point[i]=-1; add(S,1,k); for (int i=1;i<=mid;i++) add(i*n,T,k); for (int i=1;i<=m;i++) for (int j=1;j<mid;j++) add((j-1)*n+x[i],j*n+y[i],1); if (isap(S,T)==k) return true; return false; } int main() { freopen("san.in","r",stdin); freopen("san.out","w",stdout); scanf("%d%d%d",&n,&m,&k); for (int i=1;i<=m;i++) scanf("%d%d",&x[i],&y[i]); int l=0; int r=n+k+2; int ans=n+k+2; while (l<=r) { int mid=(l+r)/2; if (check(mid)) ans=min(ans,mid),r=mid-1; else l=mid+1; } if (ans==n+k+2) printf("-1\n"); else printf("%d\n",ans-1); }
相关文章推荐
- 省队集训 Day3 吴清华
- bzoj4171 or 省队集训day3 chess: Rhl的游戏
- 省队集训Round2 DAY7
- FJ省队集训DAY3 T1
- 省队集训Day3 tree
- 省队集训 Day3 杨北大
- 省队集训Day3 light
- 省队集训DAY3
- 省队集训Round2 DAY1
- 省队集训 Day3 陈姚班
- 省队集训Round2 DAY2
- 省队集训Day1 总统选举
- 暑期集训day3训练(数据结构)
- 暑期集训 DAY3
- HNOI 2016 省队集训日记
- 沈阳集训day3
- 省队集训Day1 睡觉困难综合征
- 20160124集训Day3-数学
- 省队集训 Day1 残缺的字符串
- 集训题解-Day3