您的位置:首页 > 其它

省队集训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);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: