【线段树】【树】【网络流】[UOJ#77]A+B Problem
2016-03-19 12:13
691 查看
题目描述
感谢geng给我了正确的数据范围
题目解析
首先我们可以发现如果我们不考虑有奇怪的格子,那么显然我们有ans=∑黑色的格子bi+∑白色的格子wi那么ans=∑i=1nwi+bi−∑i=1nmin{wi,bi}那么我们可以这样跑个网络流求最小割,但是我们这个时候因为多出来了一个pi的限制,那么ans=∑i=1nwi+bi−(∑白色的格子bi+∑黑色的格子wi+∑奇怪的格子pi)我们就对于每一个节点i新建一个节点i′然后连接一条流量为pi的边给他同时我们让(s,i)=bi让(i,t)=wi这样我们的网络流可以分成S和T两个集合当i属于s的时候i显然就是个黑色的了,我们这个时候让i′向所有的k连边INFk满足li≤ak≤ri那么我们分析一下发现因为存在最小割,那么就存在三种情况i为黑色,此时(s,i)为割边没有流量经过(i,i′)
i为白色,此时(i,i′)为割边那么存在满足条件
i为白色,此时(i,i′)不是割边但是因为存在最小割那么所有满足条件的k均变成了(k,t)满流视作变成了黑色,所以仍然满足条件。
因为n太大,我们要进行优化,我们可以发现对于每一次由i′连接到的k如果按照ai排序均为连续的一个区间,我们可以使用线段树维护,我们这样看作,[l,r]表示为l≤ai≤r中的每一个i提供了一个插头,我们维护的就是一个放满了插头的树,但是因为有先后顺序所以我们用可持久化线段树维护,同时如果我们出现了两个相同的ai怎么办呢,如何让两个i公用一个插头呢,显然将当前的插头连一条INF的边给上一个需要当前位置插头的插头就行了
ans=∑i=1nwi+bi−flow(s,t)
代码
#include <cstdio> #include <cstring> #include <algorithm> #include <queue> using namespace std; const int MAXN = 5000; const int MAXLOG = 13; const int INF = 0x7fffffff; struct node{ int c,v; node *next,*back; }*adj[MAXN*20],edge[1000005],*ecnt=edge; int n,a[MAXN+10],b[MAXN+10],w[MAXN+10],_l[MAXN+10],_r[MAXN+10],_p[MAXN+10],tmp[MAXN*3+10],m,s,t,ans,sump,dis[MAXN*20],num[MAXN*20], roots[MAXN+10], pcnt; struct tnode{ int ch[2]; }pool[MAXN*MAXLOG+10]; inline void addedge(int u, int v, int c) { ++ecnt; ecnt->v = v; ecnt->c = c; ecnt->next = adj[u]; ecnt->back = ecnt+1; adj[u] = ecnt; ++ecnt; ecnt->v = u; ecnt->c = 0; ecnt->next = adj[v]; ecnt->back = ecnt-1; adj[v] = ecnt; } void Insert(int &x,int y,int l,int r,int i) { x=++pcnt; pool[x]=pool[y]; if(l==r) { addedge(x+t,i,INF); if(y) addedge(x+t,y+t,INF); //处理相同的a[i] return; } int mid=(l+r)>>1; if(a[i]>mid) Insert(pool[x].ch[1],pool[y].ch[1],mid+1,r,i); else Insert(pool[x].ch[0],pool[y].ch[0],l,mid,i); if(pool[x].ch[1]) addedge(t+x,t+pool[x].ch[1],INF); if(pool[x].ch[0]) addedge(t+x,t+pool[x].ch[0],INF); } void Link(int x,int l,int r,int i) { if(l>_r[i]||_l[i]>r) return; if(_l[i]<=l&&_r[i]>=r) { addedge(n+i,t+x,INF); return; } int mid=(l+r)>>1; if(pool[x].ch[0]) Link(pool[x].ch[0],l,mid,i); if(pool[x].ch[1]) Link(pool[x].ch[1],mid+1,r,i); } int isap(int u,int augu) { if(u==t) return augu; int augv=0,v,mind=sump-1,delta; for(node *p=adj[u]; p; p=p->next) { v=p->v; if(p->c) { if(dis[u]==dis[v]+1) { delta=min(augu-augv,p->c); delta=isap(v,delta); augv+=delta; p->c-=delta; p->back->c+=delta; if(augv==augu||dis[s]>=sump) return augv; } mind=min(mind,dis[v]); } } if(!augv) { if(!--num[dis[u]]) dis[s]=sump; dis[u]=mind+1; num[dis[u]]++; } return augv; } queue<int> que; int work() { que.push(t); while(!que.empty()) { int u = que.front(); que.pop(); for(node *p=adj[u]; p; p=p->next) { if(!dis[p->v]) { dis[p->v] = dis[u] + 1; que.push(p->v); } } } dis[t] = 0; for(int i=1; i<=sump; i++) { if(dis[i] == 0) { dis[i] = sump; continue; } num[dis[i]]++; } num[dis[t]=0]++; int ret = 0; while(dis[s] < sump) ret += isap(s, INF); return ret; } inline void Read(int &u) { char ch; while((ch = getchar()), ch<'0'||ch>'9'); u = ch - '0'; while((ch = getchar()), ch>='0'&&ch<='9') u = u*10+ch-'0'; ungetc(ch, stdin); } int main() { Read(n); for(int i=1; i<=n; i++) { Read(a[i]); Read(b[i]); Read(w[i]); Read(_l[i]); Read(_r[i]); Read(_p[i]); //scanf("%d%d%d%d%d%d", &a[i], &b[i], &w[i], &_l[i], &_r[i], &_p[i]); tmp[++m] = a[i]; tmp[++m] = _l[i]; tmp[++m] = _r[i]; ans += w[i] + b[i]; } sort(tmp+1, tmp+1+m); m = unique(tmp+1, tmp+1+m) - tmp - 1; s = 2 * n + 1, t = s + 1; for(int i=1; i<=n; i++) { a[i] = lower_bound(tmp+1, tmp+1+m, a[i]) - tmp; _l[i] = lower_bound(tmp+1, tmp+1+m, _l[i]) - tmp; _r[i] = lower_bound(tmp+1, tmp+1+m, _r[i]) - tmp; addedge(s, i, b[i]); addedge(i, t, w[i]); addedge(i, i+n, _p[i]); } for(int i=1; i<=n; i++) { if(roots[i-1] != 0) Link(roots[i-1], 1, m, i); Insert(roots[i], roots[i-1], 1, m, i); } sump = t + pcnt; printf("%d\n", ans - work()); return 0; }
相关文章推荐
- C#实现获取系统目录并以Tree树叉显示的方法
- C语言实现输入一颗二元查找树并将该树转换为它的镜像
- 纯jsp打造无限层次的树代码
- 一波C语言二元查找树算法题目解答实例汇总
- php遍历树的常用方法汇总
- PHP树的深度编历生成迷宫及A*自动寻路算法实例分析
- PHP生成树的方法
- Java Swing中的表格(JTable)和树(JTree)组件使用实例
- python数据结构树和二叉树简介
- B+树到MySQL之innoDB
- ExtJS 4 树
- 数据库表TreeView树的快速生成
- Oracle 查询所有的父节点和子节点
- 多层级节点树实现
- 树的双亲存储:
- 树
- 二叉树(2)——遍历的非递归实现
- 二叉树(2)——遍历的非递归实现
- 二叉树(3)——三叉链表示的二叉树
- C#实现树结构