【CF1045A】A Last chance【贪心】【线段树优化建图】【网络流构造方案】
題意:有nnn個(gè)武器和mmm個(gè)飛船,武器有下面三種
求最多能擊破的飛船數(shù)量,并輸出一種方案。
n,m≤5×103,∑∣S∣≤105n,m\leq 5\times10^3,\sum|S|\leq10^5n,m≤5×103,∑∣S∣≤105
網(wǎng)絡(luò)流大雜燴
操作333似乎是個(gè)經(jīng)典的不可做問題。但注意到指定的三個(gè)飛船不會(huì)重復(fù),且只有333能選222個(gè),可以貪心地把所有333都覆蓋(也可以通過后面的建圖理解為什么貪心是正確的)
1、31、31、3操作直接建,222操作建個(gè)線段樹優(yōu)化建圖
具體而言,先整一棵線段樹,樹上的父結(jié)點(diǎn)向兒子連容量為 INF 的邊,葉子結(jié)點(diǎn)表示飛船,向TTT連容量為111。另開nnn個(gè)點(diǎn),表示武器,111操作流111的流量直接連,222操作拆成log?\loglog個(gè)區(qū)間連,333操作流222的流量先記下來最后連上去,這樣333操作會(huì)最先增廣,然后后面無論怎么增廣流量都是222(這也是為什么貪心是對(duì)的)
方案可以從TTT往回dfs,走有流的邊。因?yàn)橐呀?jīng)有流了,所以往這條邊走一定有合法方案,走到武器點(diǎn)的時(shí)候立刻返回,并順便退掉111的流量。
誰能告訴我怎么算數(shù)組大小啊
#include <iostream> #include <cstdio> #include <cstring> #include <cctype> #include <queue> #define MAXN 1000005 #define MAXM 10000005 using namespace std; const int INF=0x7fffffff; struct edge{int u,v,c;}e[MAXN]; int head[MAXN],cur[MAXN],nxt[MAXM],cnt=1; void insert(int u,int v,int c) {e[++cnt]=(edge){u,v,c};nxt[cnt]=head[u];head[u]=cnt; } void addnode(int u,int v,int c){insert(u,v,c),insert(v,u,0);} int dis[MAXN],S,T; bool bfs() {queue<int> q;q.push(S);memset(dis,-1,(T+5)*sizeof(int));dis[S]=0;while (!q.empty()){int u=q.front();q.pop();for (int i=head[u];i;i=nxt[i])if (e[i].c&&dis[e[i].v]==-1){dis[e[i].v]=dis[u]+1;q.push(e[i].v);if (e[i].v==T) return true;}}return false; } int dfs(int u,int f) {if (u==T||!f) return f;int used=0;for (int &i=cur[u];i;i=nxt[i])if (e[i].c&&dis[e[i].v]==dis[u]+1){int w=dfs(e[i].v,min(f,e[i].c));if (!w) continue;used+=w,f-=w;e[i].c-=w,e[i^1].c+=w;if (!f) break;}if (!used) dis[u]=-1;return used; } inline int dinic() {int mflow=0;while (bfs()) memcpy(cur,head,(T+5)*sizeof(int)),mflow+=dfs(S,INF);return mflow; } int pos[MAXN],sop[MAXN],mx; #define lc p<<1 #define rc p<<1|1 void build(int p,int l,int r) {mx=max(mx,p);if (l==r) return (void)(pos[l]=p,sop[p]=l);int mid=(l+r)>>1;build(lc,l,mid);build(rc,mid+1,r);addnode(p,lc,INF),addnode(p,rc,INF); } void query(int p,int l,int r,int ql,int qr,int u) {if (ql<=l&&r<=qr) return (void)addnode(u,p,1);if (qr<l||r<ql) return;int mid=(l+r)>>1;query(lc,l,mid,ql,qr,u),query(rc,mid+1,r,ql,qr,u); } int x[MAXN],a[MAXN],b[MAXN],c[MAXN],tot,n,m; int ans[MAXN]; int find(int u,int f) {if (mx+1<=u&&u<=mx+n) return u;for (int i=head[u];i;i=nxt[i])if (e[i].c&&e[i].v!=f){--e[i].c;++e[i^1].c;return find(e[i].v,u);}return 0; } int main() {scanf("%d%d",&n,&m);build(1,1,m);S=mx+n+1,T=S+1;for (int i=1;i<=n;i++){int type;scanf("%d",&type);if (type==0){addnode(S,mx+i,1);int k;scanf("%d",&k);while (k--){int x;scanf("%d",&x);addnode(mx+i,pos[x],1);}}if (type==1){addnode(S,mx+i,1);int l,r;scanf("%d%d",&l,&r);query(1,1,m,l,r,mx+i);}if (type==2){++tot;x[tot]=i;scanf("%d%d%d",&a[tot],&b[tot],&c[tot]);}}for (int i=1;i<=tot;i++){addnode(S,mx+x[i],2);addnode(mx+x[i],pos[a[i]],1);addnode(mx+x[i],pos[b[i]],1);addnode(mx+x[i],pos[c[i]],1);}for (int i=1;i<=m;i++) addnode(pos[i],T,1);printf("%d\n",dinic());for (int i=head[T];i;i=nxt[i])if (e[i].c){int t=find(e[i].v,T);if (t) printf("%d %d\n",t-mx,sop[e[i].v]);}return 0; }總結(jié)
以上是生活随笔為你收集整理的【CF1045A】A Last chance【贪心】【线段树优化建图】【网络流构造方案】的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【NOI2019】弹跳【二维线段树】【d
- 下一篇: 【NOI2019】斗主地【期望】【组合数