T1
费用流,拆点,把点按奇偶分类
偶数的直接拆成 \(\frac{a_i}{2}\) ,奇数的也一样,然后枚举哪一边的流量多,再给他加上就行
Code
#include<bits/stdc++.h>
#define int long long
#define rint signed
#define inf 0x3f3f3f3f3f3f3f3f
using namespace std;
inline int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
int n,ans=inf,p,U,S,T;
int a[60],c[60][60],trans[60];
int L[60],R[60];
namespace FLOW{
int COST;
int dis[1010],q[1010],h,t;
int head[1010],ver[6000],to[6000],edge[6000],cost[6000],tot=1;
bool inq[1010],vis[1010];
inline void add(int x,int y,int z,int w){
ver[++tot]=y;edge[tot]=z;cost[tot]= w;to[tot]=head[x];head[x]=tot;
ver[++tot]=x;edge[tot]=0;cost[tot]=-w;to[tot]=head[y];head[y]=tot;
}
inline bool spfa(){
for(int i=1;i<=T;i++) dis[i]=inf,inq[i]=0;
dis[S]=0,q[h=t=1]=S,inq[S]=1;memset(vis,0,sizeof(vis));
while(h<=t){
int x=q[h++];inq[x]=0;
for(int i=head[x];i;i=to[i]) if(edge[i]){
int y=ver[i];
if(dis[y]>dis[x]+cost[i]){
dis[y]=dis[x]+cost[i];
if(!inq[y]) q[++t]=y,inq[y]=1;
}
}
}
return dis[T]!=inf;
}
int dfs(int x,int in){
if(x==T) return in;
int res=in,go;vis[x]=1;
for(int i=head[x];i;i=to[i]) if(edge[i]){
int y=ver[i];
if(vis[y]) continue;
if(dis[y]==dis[x]+cost[i]){
go=dfs(y,min(res,edge[i]));
res-=go,edge[i]-=go,edge[i^1]+=go;
COST+=go*cost[i];
}
if(!res) break;
}
return in-res;
}
inline void clear(){for(int i=1;i<=T;i++) head[i]=0;tot=1;COST=0;}
inline int MinCost(){while(spfa()) dfs(S,inf);return COST;}
}using FLOW::add;
signed main(){
#ifdef LOCAL
freopen("in","r",stdin);
freopen("out","w",stdout);
#endif
freopen("match.in","r",stdin);
freopen("match.out","w",stdout);
n=read();S=n*2+1,T=n*2+2;
for(int i=1;i<=n;i++) a[i]=read();
for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) c[i][j]=read();
for(int i=1;i<=n;i++) if(a[i]&1) trans[++p]=i;if(p&1) puts("-1"),exit(0);
U=(1<<p)-1;
for(int sta=0;sta<=U;sta++) if(__builtin_popcount(sta)==p/2){
for(int i=1;i<=n;i++) L[i]=R[i]=a[i]/2;
for(int i=1;i<=p;i++) if(sta>>(i-1)&1) L[trans[i]]++;else R[trans[i]]++;
FLOW::clear();
for(int i=1;i<=n;i++) add(S,i,L[i],0),add(i+n,T,R[i],0);
for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) add(i,j+n,inf,c[i][j]);
ans=min(ans,FLOW::MinCost());
}
printf("%lld\n",ans);
return 0;
}
T2
对于每个节点都维护一些线段,只用记录他的左右端点
合并的时候考虑哪一条线段作为第一条线段,再用状压 \(dp\) 出以这个线段为左端点时的最小的右端点
注意把劣的去掉,同时在状压的过程中记录合并的顺序
Code
#include<bits/stdc++.h>
#define int long long
#define rint signed
#define inf 0x3f3f3f3f
using namespace std;
inline int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
int n;
struct seg{
int l,r,id;
inline bool operator<(const seg &b)const{return (l==b.l)?r<b.r:l<b.l;}
};
map<int,seg>mp;
vector<int>g[100010],ans[100010];
vector<seg>vec[100010],tmp;
int f[100010],ff[100010],son[100010],id[100010];
void dfs1(int x){
if(!g[x].size()) return ;int p=0;
for(auto y:g[x]) dfs1(y),son[y]=++p;
if(g[x].size()==1) return swap(vec[x],vec[g[x][0]]),void();
int U=(1<<(g[x].size()-1))-1;
mp.clear();tmp.clear();seg t;
for(int i=0;i<g[x].size();i++){
int y=g[x][i];
for(int j=0;j<vec[y].size();j++){
t=vec[y][j];t.id=i;
tmp.emplace_back(t);
}
}
sort(tmp.begin(),tmp.end());reverse(tmp.begin(),tmp.end());
int pre=inf;
for(int i=0;i<tmp.size();i++){
t=tmp[i];
int y=g[x][t.id],l=t.l,r=t.r,pp=0;
for(int j=0;j<g[x].size();j++) if(j!=t.id) id[++pp]=g[x][j];
for(int sta=0;sta<=U;sta++) f[sta]=inf;f[0]=r,ff[0]=son[y];
for(int sta=0;sta<=U;sta++) if(f[sta]<=100000){
t.l=f[sta]+1,t.r=0;
for(int j=1,pos,ed;j<=pp;j++) if(!((sta>>(j-1))&1)){
ed=vec[id[j]].size();
pos=lower_bound(vec[id[j]].begin(),vec[id[j]].end(),t)-vec[id[j]].begin();
if(pos!=ed&&vec[id[j]][pos].r<f[sta|1<<(j-1)]){
f[sta|1<<(j-1)]=vec[id[j]][pos].r;
ff[sta|1<<(j-1)]=ff[sta]*10+son[id[j]];
}
}
}
if(f[U]<=100000&&f[U]<pre) pre=f[U],mp[l].r=f[U],mp[l].id=ff[U];
}
auto iter=mp.begin();
if(iter==mp.end()) puts("No"),exit(0);
while(iter!=mp.end()){
t=(*iter).second,t.l=(*iter).first;
vec[x].emplace_back(t);
iter++;
}
}
void dfs2(int x,int l,int r){
if(g[x].size()==0) return ans[x].emplace_back(l),void();
if(g[x].size()==1) return ans[x].emplace_back(g[x][0]),swap(vec[x],vec[g[x][0]]),dfs2(g[x][0],l,r);
seg t=(seg){l,r,0};
int pos=lower_bound(vec[x].begin(),vec[x].end(),t)-vec[x].begin();
int id=vec[x][pos].id;
while(id) ans[x].emplace_back(g[x][id%10-1]),id/=10;
reverse(ans[x].begin(),ans[x].end());t.r=0;
for(int i=0;i<ans[x].size();i++){
int y=ans[x][i];
int pos=lower_bound(vec[y].begin(),vec[y].end(),t)-vec[y].begin();
t=vec[y][pos];
dfs2(y,t.l,t.r);
t.l=t.r+1;t.r=0;
}
}
signed main(){
#ifdef LOCAL
freopen("in","r",stdin);
freopen("out","w",stdout);
#endif
freopen("sort.in","r",stdin);
freopen("sort.out","w",stdout);
n=read();
for(int i=1,op,k;i<=n;i++){
op=read();
if(op==1){
k=read();
for(int j=1;j<=k;j++) g[i].emplace_back(read());
}else{
k=read();
for(int j=1,x;j<=k;j++){x=read();vec[i].emplace_back((seg){x,x,0});}
sort(vec[i].begin(),vec[i].end());
}
}
dfs1(1);puts("Yes");
dfs2(1,vec[1][0].l,vec[1][0].r);
for(int i=1;i<=n;i++,puts("")) for(int j=0;j<ans[i].size();j++) printf("%lld ",ans[i][j]);
return 0;
}
T3
考虑 \(O(n^2)\) 的暴力,对每个点都把他能直接传染到的点和他连边
然后再用 \(tarjan\) 缩点,最后剩下几个没有入度的点,答案就是几
考虑用点分治来优化这个过程
对于每个分治中心,把所有的路径长度都找出来
对每个长度都分别建立虚点,由长向短依次连边
再看每个点,由长度大于等于他的第一个虚点连边,再由他向他能传染到的跨过分治中心的最远的点连边
这里只考虑跨过分治中心的,没有跨过的会在其他地方考虑到
最后再用 \(tarjan\) 缩点,找到没有入度的点就行
Code
#include<bits/stdc++.h>
#define int long long
#define rint signed
#define inf 0x3f3f3f3f
using namespace std;
inline int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
int n,ans,deg[4300010],r[300010],N;
rint head[300010],ver[600010],to[600010],tot;
int edge[600010];
rint dfn[4300010],low[4300010],clo,mn[4300010];
rint scc[4300010],col,stk[4300010],p;
int S,rt,mxdis;
rint siz[4300010],mx[4300010],id[4300010];
bool vis[4300010];
vector<rint>g[4100000],gg[3420000];
vector<int>vec;
queue<int>q;
inline void add(rint x,rint y,rint z){ver[++tot]=y;edge[tot]=z;to[tot]=head[x];head[x]=tot;}
void tarjan(int x){
dfn[x]=low[x]=++clo;vis[x]=1;stk[++p]=x;
for(auto y:g[x]){
if(!dfn[y]){tarjan(y);low[x]=min(low[x],low[y]);}
else if(vis[y]) low[x]=min(low[x],dfn[y]);
}
if(dfn[x]==low[x]){
rint k;col++;mn[col]=N+1;
do{k=stk[p--];scc[k]=col;vis[k]=0;mn[col]=min(mn[col],k);}while(k!=x);
}
}
void getrt(int x,int fa){
siz[x]=1,mx[x]=0;
for(rint i=head[x];i;i=to[i]){
int y=ver[i];
if(y==fa||vis[y]) continue;
getrt(y,x);siz[x]+=siz[y];mx[x]=max(mx[x],siz[y]);
}
mx[x]=max(mx[x],(rint)S-siz[x]);
if(mx[x]<mx[rt]) rt=x;
}
void getdis(int x,int fa,int dis){
mxdis=max(mxdis,dis);vec.emplace_back(dis);
for(rint i=head[x];i;i=to[i]){
int y=ver[i];
if(y==fa||vis[y]) continue;
getdis(y,x,dis+edge[i]);
}
}
void dfs2(int x,int fa,int dis){
int pos=lower_bound(vec.begin(),vec.end(),dis)-vec.begin(),range;
g[id[pos]].emplace_back(x);
range=min(mxdis,r[x]-dis);
if(range>=0){
pos=upper_bound(vec.begin(),vec.end(),range)-vec.begin();
if(pos) g[x].emplace_back(id[pos-1]);
}
for(rint i=head[x];i;i=to[i]){
int y=ver[i];
if(y==fa||vis[y]) continue;
dfs2(y,x,dis+edge[i]);
}
}
inline void calc(int x){
vec.clear();mxdis=-1;getdis(x,0,0);
sort(vec.begin(),vec.end());
vec.erase(unique(vec.begin(),vec.end()),vec.end());
for(rint i=0;i<vec.size();i++) id[i]=++N;dfs2(x,0,0);
for(rint i=1;i<vec.size();i++) g[id[i]].emplace_back(id[i-1]);
}
void solve(int x){
vis[x]=1;calc(x);
for(rint i=head[x];i;i=to[i]){
int y=ver[i];
if(vis[y]) continue;
rt=0;getrt(y,0);
S=siz[y];mx[rt=0]=inf;
getrt(y,0);solve(rt);
}
}
signed main(){
#ifdef LOCAL
freopen("in","r",stdin);
freopen("out","w",stdout);
#endif
freopen("infect.in","r",stdin);
freopen("infect.out","w",stdout);
N=n=read();for(rint i=1;i<=n;i++) r[i]=read();
for(rint i=1,x,y,z;i<n;i++){
x=read(),y=read(),z=read();
add(x,y,z);add(y,x,z);
}
S=n;mx[rt=0]=inf;
getrt(1,0);solve(rt);
memset(vis,0,sizeof(vis));
for(rint i=1;i<=N;i++) if(!dfn[i]) tarjan(i);
for(rint i=1;i<=N;i++) for(auto y:g[i]) if(scc[i]!=scc[y]) deg[scc[y]]++,gg[scc[i]].emplace_back(scc[y]);
for(rint i=1;i<=col;i++) if(!deg[i]) q.push(i);
cerr<<col<<endl;
memset(vis,0,sizeof(vis));
while(!q.empty()){
int x=q.front();q.pop();
if(!vis[x]&&mn[x]<=n) ans++,vis[x]=1;
for(auto y:gg[x]){
deg[y]--,vis[y]|=vis[x];
if(!deg[y]) q.push(y);
}
}
printf("%lld\n",ans);
return 0;
}