BZOJ 3257 JZOJ 3347 树的难题
分析
树形dp,设
d
p
[
x
]
[
i
]
[
j
]
dp[x][i][j]
dp[x][i][j]表示第
x
x
x个点,有无黑点,白点个数为
j
j
j,若
j
≥
2
j\geq 2
j≥2视作2的最小代价
那么
d
p
[
x
]
[
i
]
[
j
]
=
∑
s
o
n
∈
i
min
{
d
p
[
s
o
n
]
[
i
′
]
[
j
′
]
}
+
w
dp[x][i][j]=\sum_{son\in i}\min\{dp[son][i'][j']\}+w
dp[x][i][j]=∑son∈imin{dp[son][i′][j′]}+w
代码
#include <cstdio>
#include <cctype>
#include <cstring>
#define rr register
using namespace std;
typedef long long ll;
const ll inf=1e14,N=3e5+1;
struct node{int y,w,next;}e[N<<1|1];
int k,ls[N],a[N],n,head,tail; ll dp[N][2][3];
inline signed iut(){
rr int ans=0; rr char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
return ans;
}
inline void add(int x,int y,int w){
e[++k]=(node){y,w,ls[x]}; ls[x]=k;
e[++k]=(node){x,w,ls[y]}; ls[y]=k;
}
inline ll min(ll a,ll b){return a<b?a:b;}
signed main(){
for (rr int t=iut();t;--t){
k=head=tail=1; memset(ls,0,sizeof(ls));
n=iut(); rr int stx[n+1],sfa[n+1];
for (rr int i=1;i<=n;++i) a[i]=iut();
for (rr int i=1,u,v;i<n;++i)
u=iut(),v=iut(),add(u,v,iut());
stx[1]=sfa[1]=1;
while (head<=tail){
rr int x=stx[head],fa=sfa[head++];
for (rr int i=ls[x];i;i=e[i].next)
if (e[i].y!=fa) stx[++tail]=e[i].y,sfa[tail]=x;
}
for (rr int h=tail;h;--h){
rr int x=stx[h],fa=sfa[h];
for (rr int p1=0;p1<2;++p1)
for (rr int p2=0;p2<3;++p2) dp[x][p1][p2]=inf;
dp[x][a[x]==0][a[x]==1]=0;
for (rr int i=ls[x];i;i=e[i].next)
if (e[i].y!=fa){
rr ll f[2][3];
for (rr int p1=0;p1<2;++p1)
for (rr int p2=0;p2<3;++p2) f[p1][p2]=inf;
for (rr int p1=0;p1<2;++p1)
for (rr int p2=0;p2<3;++p2) if (dp[x][p1][p2]!=inf)
for (rr int p3=0;p3<2;++p3)
for (rr int j=0;j<3;++j) if (dp[e[i].y][p3][j]!=inf){
rr int z1=p1+p3>=1,z2=min(p2+j,2);
f[z1][z2]=min(f[z1][z2],dp[x][p1][p2]+dp[e[i].y][p3][j]);
if (!p3||j<2) f[p1][p2]=min(f[p1][p2],dp[x][p1][p2]+dp[e[i].y][p3][j]+e[i].w);
}
memcpy(dp[x],f,sizeof(f));
}
}
printf("%lld\n",min(min(min(dp[1][0][0],dp[1][0][1]),min(dp[1][0][2],dp[1][1][0])),dp[1][1][1]));
}
return 0;
}
BZOJ 3258 JZOJ 3348 秘密任务
分析
这是一道求最小割的题目,对于第二问,最小割是否唯一,当且仅当割边的两头属于起点或终点,用tarjan解决
代码
#include <cstdio>
#include <cctype>
#include <cstring>
#include <queue>
#define cle(TEMP,_T) memset(TEMP,_T,sizeof(TEMP))
#define min(a,b) ((a)<(b)?(a):(b))
#define rr register
using namespace std;
typedef unsigned uit;
const uit inf=4e9+101;
struct node{uit y,w,next;}e[8011],E[8011]; bool v[401]; long long dis[401];
uit k1,k2,ls[401],hs[401],dfn[401],low[401],stack[401],a[401],dcc[401],s,t,n,m,top,DCC,ans,flag;
inline signed iut(){
rr uit ans=0; rr char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
return ans;
}
inline void Add(uit x,uit y,uit w){
E[++k2]=(node){y,w,hs[x]},hs[x]=k2;
E[++k2]=(node){x,w,hs[y]},hs[y]=k2;
}
inline void add(uit x,uit y,uit w){
e[++k1]=(node){y,w,ls[x]},ls[x]=k1;
e[++k1]=(node){x,0,ls[y]},ls[y]=k1;
}
inline void spfa(){
for (rr uit i=1;i<=n;++i) dis[i]=1e14,v[i]=0;
dis[1]=0,v[1]=1; rr deque<uit>q; q.push_front(1);
while (q.size()){
rr uit x=q.front(); q.pop_front();
for (rr uit i=hs[x];i;i=E[i].next)
if (dis[E[i].y]>dis[x]+E[i].w){
dis[E[i].y]=dis[x]+E[i].w;
if (!v[E[i].y]){
v[E[i].y]=1;
if (q.size()&&dis[E[i].y]<dis[q.front()]) q.push_front(E[i].y);
else q.push_back(E[i].y);
}
}
v[x]=0;
}
}
inline void Dfs(uit x){
if (v[x]) return; v[x]=1;
for (rr uit i=hs[x];i;i=E[i].next)
if (dis[x]==dis[E[i].y]+E[i].w)
add(E[i].y,x,min(a[x],a[E[i].y])),Dfs(E[i].y);
}
inline signed bfs(uit s){
for (rr uit i=1;i<=t;++i) dis[i]=0;
queue<uit>q; q.push(s); dis[s]=1;
while (q.size()){
rr uit x=q.front(); q.pop();
for (rr uit i=ls[x];i;i=e[i].next)
if (e[i].w>0&&!dis[e[i].y]){
dis[e[i].y]=dis[x]+1;
if (e[i].y==t) return 1;
q.push(e[i].y);
}
}
return 0;
}
inline signed dfs(uit x,uit now){
if (x==t||!now) return now;
rr uit rest=0,f;
for (rr uit i=ls[x];i;i=e[i].next)
if (e[i].w>0&&dis[e[i].y]==dis[x]+1){
rest+=(f=dfs(e[i].y,min(now-rest,e[i].w)));
e[i].w-=f; e[i^1].w+=f;
if (now==rest) return rest;
}
if (!rest) dis[x]=0;
return rest;
}
inline signed dinic(){
rr uit ans=0;
while (bfs(s)) ans+=dfs(s,inf);
return ans;
}
inline void tarjan(uit x){
dfn[x]=low[x]=++dfn[0],stack[++top]=x;
for (rr uit i=ls[x];i;i=e[i].next)
if (e[i].w){
if (!dfn[e[i].y]) tarjan(e[i].y),low[x]=min(low[x],low[e[i].y]);
else if (!dcc[e[i].y]) low[x]=min(low[x],dfn[e[i].y]);
}
if (dfn[x]==low[x]){
++DCC;
for (uit y;y!=x;--top) dcc[y=stack[top]]=DCC;
}
}
signed main(){
for (rr uit T=iut();T;--T){
cle(hs,0),cle(ls,0),cle(dfn,0),cle(low,0),cle(dcc,0),
n=iut(),m=iut(),k1=k2=1,flag=DCC=top=0;
for (rr uit i=1;i<n;++i) a[i]=iut(); a[n]=inf;
for (rr uit i=1,x,y;i<=m;++i) x=iut(),y=iut(),Add(x,y,iut());
spfa(),s=1,t=n,Dfs(n),ans=dinic();
for (rr uit i=1;i<=n;++i) if (!dfn[i]) tarjan(i);
for (rr uit i=2;i<=k1;i+=2) if (!e[i].w){
if (dcc[e[i].y]!=dcc[e[i^1].y]&&!(dcc[e[i^1].y]==dcc[1]&&dcc[e[i].y]==dcc[n])) flag=1;
if (dcc[e[i^1].y]==dcc[1]&&dcc[e[i].y]==dcc[n]&&a[e[i].y]==a[e[i^1].y]) flag=1;
}
!flag?printf("Yes "):printf("No "); printf("%u\n",ans);
}
return 0;
}
JZOJ 3379 查询
题目
多组询问,询问把最多5个区间的数扔入multiset,问第 k k k小
分析
主席树裸题,不多解释
代码
#include <cstdio>
#include <cctype>
#include <algorithm>
#define rr register
using namespace std;
const int N=200101;
int a[N],b[N],rt[N],L[5],R[5],tot,n,q,m;
inline signed iut(){
rr int ans=0; rr char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
return ans;
}
inline void print(int ans){
if (ans>9) print(ans/10);
putchar(ans%10+48);
}
struct Chair{
int w[N*20],ls[N*20],rs[N*20],cnt;
inline void build(int &rt,int l,int r){
w[rt=++cnt]=0; rr int mid=(l+r)>>1;
if (l<r) build(ls[rt],l,mid),build(rs[rt],mid+1,r);
}
inline void update(int &rt,int l,int r,int k){
rr int trt=++cnt,mid=(l+r)>>1;
ls[trt]=ls[rt],rs[trt]=rs[rt],w[trt]=w[rt]+1,rt=trt;
if (l==r) return;
k<=mid?update(ls[trt],l,mid,k):update(rs[trt],mid+1,r,k);
}
inline signed query(int l,int r,int k){
if (l==r) return l;
rr int x=0,mid=(l+r)>>1;
for (rr int i=0;i<tot;++i) x+=w[ls[R[i]]]-w[ls[L[i]]];
for (rr int i=0;i<tot;++i)
x>=k?(L[i]=ls[L[i]],R[i]=ls[R[i]]):(L[i]=rs[L[i]],R[i]=rs[R[i]]);
return x>=k?query(l,mid,k):query(mid+1,r,k-x);
}
}Tre;
signed main(){
n=iut(); q=iut();
for (rr int i=1;i<=n;++i) b[i]=a[i]=iut();
sort(b+1,b+1+n); m=unique(b+1,b+1+n)-b-1;
Tre.cnt=0; Tre.build(rt[0],1,m);
for (rr int i=1;i<=n;++i)
Tre.update(rt[i]=rt[i-1],1,m,lower_bound(b+1,b+1+m,a[i])-b);
while (q--){
tot=iut(); rr int k=iut();
for (rr int i=0;i<tot;++i) L[i]=rt[iut()-1],R[i]=rt[iut()];
print(b[Tre.query(1,m,k)]),putchar(10);
}
return 0;
}