4849: [Neerc2016]Mole Tunnels

来源:互联网 发布:紫金桥软件 编辑:程序博客网 时间:2024/05/17 08:16

4849: [Neerc2016]Mole Tunnels

Time Limit: 20 Sec Memory Limit: 128 MB
Submit: 34 Solved: 15
[Submit][Status][Discuss]
Description

鼹鼠们在底下开凿了n个洞,由n-1条隧道连接,对于任意的i>1,第i个洞都会和第i/2(取下整)个洞间有一条隧
道,第i个洞内还有ci个食物能供最多ci只鼹鼠吃。一共有m只鼹鼠,第i只鼹鼠住在第pi个洞内,一天早晨,前k只
鼹鼠醒来了,而后n-k只鼹鼠均在睡觉,前k只鼹鼠就开始觅食,最终他们都会到达某一个洞,使得所有洞的ci均大
于等于该洞内醒着的鼹鼠个数,而且要求鼹鼠行动路径总长度最小。现对于所有的1<=k<=m,输出最小的鼹鼠行动
路径的总长度,保证一定存在某种合法方案。
Input

第一行两个数n,m(1<=n,m<=100000),表示有n个洞,m只鼹鼠。
第二行n个整数ci表示第i个洞的食物数。
第三行m个整数pi表示第i只鼹鼠所在洞pi。
Output

输出一行m个整数,第i个整数表示当k=i时最小的鼹鼠行动路径总长度。
Sample Input

5 4

0 0 4 1 1

2 4 5 2
Sample Output

1 1 2 4
HINT

Source

考虑贪心的策略
k的答案肯定可以在k1的基础上,修改一些路径得到
将原图对应到一棵二叉树
对于每条隧道,记录当前方案中,
有多少只鼹鼠从下往上或是从上往下通过
显然这两种情况只能存在其中一种,否则可以相互抵消让答案更优
因为题目中边的限制,这棵二叉树的深度为log2n
暴力枚举第k只鼹鼠可能的路径
先枚举它往上走的步数,然后往下找到目标点
对于每条隧道,如果这只鼹鼠要从下往上通过,
而之前已经有x(x>0)只鼹鼠从上往下通过
那么我们通过交换这只鼹鼠和任意一只鼹鼠的后续路径
这条边通过的鼹鼠数量就减少了
于是这样的边权值可以标为1
每次找出路径都可以转换为二叉树上的区间修改
dfs序+线段数大力维护一下,每次贪心就行了

#include<iostream>#include<cstdio>#include<algorithm>#include<cmath>#include<cstring>#include<vector>#include<queue>#include<set>#include<map>#include<stack>#include<bitset>#include<ext/pb_ds/priority_queue.hpp>#define min(a,b) ((a) < (b) ? (a) : (b))using namespace std;const int T = 4;const int INF = ~0U>>1;const int maxn = 1E5 + 10;int n,m,dfs_clock,now,len,Ans,dfn[maxn],End[maxn],c[maxn],val[maxn*T]    ,Name[maxn],L[maxn],A[maxn],Num[maxn*T],Min[maxn*T],Mark[maxn*T];inline void Dfs(int x){    dfn[x] = ++dfs_clock; Name[dfs_clock] = x;    if ((x<<1) <= n) L[x<<1] = L[x] + 1,Dfs(x<<1);    if ((x<<1|1) <= n) L[x<<1|1] = L[x] + 1,Dfs(x<<1|1);    End[x] = dfs_clock;}inline void maintain(int o){    int lc = (o << 1),rc = (o << 1 | 1);    if (Min[lc] < Min[rc])        Min[o] = Min[lc],Num[o] = Num[lc];    else Min[o] = Min[rc],Num[o] = Num[rc];}inline void pushdown(int o,int l,int r){    if (!Mark[o]) return;    if (Min[o] != INF) Min[o] += Mark[o];    if (l == r) {val[o] += Mark[o]; Mark[o] = 0; return;}    Mark[o<<1] += Mark[o]; Mark[o<<1|1] += Mark[o]; Mark[o] = 0;}inline void Build(int o,int l,int r){    if (l == r)    {        if (!c[Name[l]]) Min[o] = INF;        else Min[o] = L[Name[l]],Num[o] = Name[l];        val[o] = L[Name[l]]; return;    }    int mid = l + r >> 1;    Build(o<<1,l,mid); Build(o<<1|1,mid+1,r);    maintain(o);}inline void Search(int o,int l,int r,int ql,int qr){    pushdown(o,l,r);    if (Min[o] >= len) return;    if (ql <= l && r <= qr)    {        if (Min[o] < len)            len = Min[o],now = Num[o];        return;    }    int mid = l + r >> 1;    if (ql <= mid) Search(o<<1,l,mid,ql,qr);    if (qr > mid) Search(o<<1|1,mid+1,r,ql,qr);}inline int Query(int o,int l,int r,int pos){    pushdown(o,l,r); if (l == r) return val[o]; int mid = l + r >> 1;    return pos <= mid ? Query(o<<1,l,mid,pos) : Query(o<<1|1,mid+1,r,pos);}inline void Delete(int o,int l,int r,int pos){    pushdown(o,l,r);    if (l == r)    {        Min[o] = INF; Num[o] = 0; return;    }    int mid = l + r >> 1;    if (pos <= mid) Delete(o<<1,l,mid,pos); else pushdown(o<<1,l,mid);    if (pos > mid) Delete(o<<1|1,mid+1,r,pos); else pushdown(o<<1|1,mid+1,r);    maintain(o);}inline void Modify(int o,int l,int r,int ql,int qr,int k){    if (ql <= l && r <= qr)    {        Mark[o] += k; pushdown(o,l,r); return;    }    int mid = l + r >> 1; pushdown(o,l,r);    if (ql <= mid) Modify(o<<1,l,mid,ql,qr,k); else pushdown(o<<1,l,mid);    if (qr > mid) Modify(o<<1|1,mid+1,r,ql,qr,k); else pushdown(o<<1|1,mid+1,r);    maintain(o);}inline void Walk(int x,int y){    --c[y]; if (!c[y]) Delete(1,1,n,dfn[y]);    while (L[x] > L[y])    {        if (!A[x]) Modify(1,1,n,dfn[x],End[x],-2);        ++A[x]; x >>= 1;    }    while (L[y] > L[x])    {        if (A[y] == 1) Modify(1,1,n,dfn[y],End[y],2);        --A[y]; y >>= 1;    }    while (x != y)    {        if (!A[x]) Modify(1,1,n,dfn[x],End[x],-2);        if (A[y] == 1) Modify(1,1,n,dfn[y],End[y],2);        ++A[x]; x >>= 1; --A[y]; y >>= 1;    }}inline int getint(){    char ch = getchar(); int ret = 0;    while (ch < '0' || '9' < ch) ch = getchar();    while ('0' <= ch && ch <= '9')        ret = ret * 10 + ch - '0',ch = getchar();    return ret;}int main(){    #ifdef DMC        freopen("DMC.txt","r",stdin);        freopen("test.txt","w",stdout);    #endif    n = getint(); m = getint();    for (int i = 1; i <= n; i++) c[i] = getint();    Dfs(1); Build(1,1,n);    for (int i = 1; i <= m; i++)    {        int x = getint(),y,mi,sum;        len = INF; Search(1,1,n,dfn[x],End[x]);        if (len != INF) len -= Query(1,1,n,dfn[x]);        y = now; mi = len; sum = A[x] >= 0 ? 1 : -1;        for (int z = x >> 1,pos = x & 1; z; pos = z & 1,sum += A[z] >= 0 ? 1 : -1,z >>= 1)        {            int Nex = (z << 1) | (pos ^ 1); len = INF;            if (c[z] > 0 && sum < mi) mi = sum,y = z;            if (Nex > n) continue;            Search(1,1,n,dfn[Nex],End[Nex]);            if (len == INF) continue;            len -= Query(1,1,n,dfn[z]);            if (len + sum < mi) mi = len + sum,y = now;        }        Walk(x,y); Ans += mi; printf("%d ",Ans);    }    return 0;}
0 0