今天本来是LCT强化练习,,可是我硬是调了一天的splay,,,令人绝望
早上的时候看到了一道网络流跟以前的一道考试题非常像果断水过bzoj1287
我们将小朋友和卡片分别建点,如果小朋友没有这张卡,那么就从该颜色往小朋友连一条流量为1的边,如果小朋友拥有某张卡片超过一张,那么就从小朋友向某颜色连一条流量为小朋友拥有的该颜色卡片数减一的边,源点和汇点就类似的用小C的卡片数来连边,
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
struct data_l{int to,nxt,v;}lin[1000005];
int n,top=1,hed[1005],d[1005],que[100005],s,t,m,ans;
void add_l(int a,int b,int c)
{
lin[++top].to=b;lin[top].v=c;
lin[top].nxt=hed[a];hed[a]=top;
lin[++top].to=a;lin[top].v=0;
lin[top].nxt=hed[b];hed[b]=top;
}
bool bfs()
{
memset(d,-1,sizeof(d));
int f=0,l=0;
que[l++]=s;d[s]=0;
while(f<l)
{
int x=que[f++];
for(int i=hed[x];i;i=lin[i].nxt)
{
int y=lin[i].to;
if(lin[i].v<=0||d[y]!=-1)continue;
d[y]=d[x]+1;
que[l++]=y;
}
}
if(d[t]==-1)return false;
return true;
}
int dinic(int a,int now)
{
//cout<<"*"<<endl;
if(a==t||now<=0)return now;
int y=0;
for(int i=hed[a];i;i=lin[i].nxt)
{
int b=lin[i].to;
if(d[b]!=d[a]+1||lin[i].v<=0)continue;
int x=dinic(b,min(now,lin[i].v));
now-=x;y+=x;
lin[i].v-=x;lin[i^1].v+=x;
}
if(!y)d[a]=-1;
return y;
}
int main()
{
scanf("%d%d",&n,&m);
s=1;t=n+m+1;
for(int i=1;i<=m;i++)
{
int x;
scanf("%d",&x);
if(x>1)add_l(s,i+n,x-1);
if(!x) add_l(i+n,t,1);
if(x>0)ans++;
}
for(int i=2;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
int x;
scanf("%d",&x);
if(!x)add_l(j+n,i,1);
else if(x>1)add_l(i,j+n,x-1);
}
}
while(bfs()){ans+=dinic(s,t);}
printf("%d",ans);
return 0;
}
emm网络流会了建图就没难度了,,,
然后呢,水了一道splay的题,bzoj1552,同时这道题也是一道双倍经验bzoj3506
简单来说这道题只需要支持一个翻转标记就可以了,提前把序列排序并记录节点,然后查询siz并翻转;
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
struct data_p{int pos,num;}pot[100005];
struct data_t{int lson,rson,fa,siz,rev;}tre[400005];
int n,qst[100005],root,lst=1,stk[100005],m;
bool cmp(data_p a,data_p b){return a.num<b.num||(a.num==b.num&&a.pos<b.pos);}
void updata(int a){tre[a].siz=tre[tre[a].lson].siz+tre[tre[a].rson].siz+1;}
void print()
{
for(int i=1;i<=n+2;i++)
cout<<i<<" "<<tre[i].lson<<"*"<<tre[i].rson<<" "<<tre[i].fa<<" "<<tre[i].siz<<" "<<tre[i].rev<<endl;
cout<<endl;
}
void push_(int a)
{
if(!tre[a].rev)return;
tre[tre[a].lson].rev^=1;
tre[tre[a].rson].rev^=1;
swap(tre[a].lson,tre[a].rson);
tre[a].rev=0;
}
int build(int l,int r,int f)
{
if(l>r)return 0;
int mid=(l+r)/2;tre[mid].fa=f;
if(l==r){tre[mid].siz=1;return l;}
tre[mid].lson=build(l,mid-1,mid);
tre[mid].rson=build(mid+1,r,mid);
updata(mid);return mid;
}
void ratlt(int a)
{
int b=tre[a].fa,c=tre[b].fa;
tre[b].rson=tre[a].lson;
if(tre[a].lson)tre[tre[a].lson].fa=b;
tre[a].fa=c;
if(c)
{
if(tre[c].lson==b)tre[c].lson=a;
else tre[c].rson=a;
}
tre[a].lson=b;tre[b].fa=a;
updata(b);updata(a);
}
void ratrt(int a)
{
int b=tre[a].fa,c=tre[b].fa;
tre[b].lson=tre[a].rson;
if(tre[a].rson)tre[tre[a].rson].fa=b;
tre[a].fa=c;
if(c)
{
if(tre[c].lson==b)tre[c].lson=a;
else tre[c].rson=a;
}
tre[a].rson=b;tre[b].fa=a;
updata(b);updata(a);
}
void splay(int a,int gfa)
{
int top=0,k=a;push_(gfa);
while(k!=gfa){stk[++top]=k;k=tre[k].fa;}
while(top){push_(stk[top--]);}
while(tre[a].fa!=gfa)
{
int b=tre[a].fa,c=tre[b].fa;
if(c==gfa)
{
if(tre[b].lson==a)ratrt(a);
else ratlt(a);
}
else
{
if(tre[c].lson==b)
{
if(tre[b].lson==a)ratrt(b),ratrt(a);
else ratlt(a),ratrt(a);
}
else
{
if(tre[b].lson==a)ratrt(a),ratlt(a);
else ratlt(b),ratlt(a);
}
}
}
updata(a);
}
int find_r(int a)
{
push_(a);a=tre[a].rson;push_(a);
while(tre[a].lson)a=tre[a].lson,push_(a);
return a;
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++){scanf("%d",&pot[i].num);pot[i].pos=i;}
sort(pot+1,pot+n+1,cmp);
for(int i=1;i<=n;i++)qst[i]=pot[i].pos+1;
root=build(1,n+2,0);
for(int i=1;i<n;i++)
{
int x=qst[i];
splay(x,0);root=x;
printf("%d ",tre[tre[x].lson].siz);
x=find_r(x);
splay(lst,0);splay(x,lst);root=lst;
tre[tre[x].lson].rev^=1;
lst=qst[i];
}
printf("%d",n);
return 0;
}
然后整整一下午都在调的题 bzoj3786,本来自己本机测试已经非常完美了,但是交上去之后始终是RE,最后要到数据发现好像是
就先不放代码丢人了,,由于我的splay是罕见的数组版所以始终找不到好的标程去对拍,,,GG