【DFS序】【莫队算法】【权值分块】bzoj2809 [Apio2012]dispatching

题意:在树中找到一个点i,并且找到这个点子树中的一些点组成一个集合,使得集合中的所有点的c之和不超过M,且Li*集合中元素个数和最大
首先,我们将树处理出dfs序,将子树询问转化成区间询问。
然后我们发现,对于单一节点来说,“使得集合中的所有点的c之和不超过M,且Li*集合中元素个数和最大”可以贪心地搞,即优先选择c较小的点。(<--这正是主席树/权值线段树/权值分块的工作)
但是我们需要枚举所有节点,从他们中选一个最大的。
既然有dfs序了,那么就是无修改的区间询问咯。(<--莫队的工作) 但是莫队转移的过程中,主席树/权值线段树的插入/删除无法承受。(当然主席树根本就用不着莫队,也可以解决这个问题,但这不是这篇文章要介绍的) 权值分块的插入/删除是O(1)的,查询是O(sqrt(n))的,总复杂度仍是O(n*sqrt(n))的。
编程复杂度较低,常数较小。
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long ll;
ll sumv[330],m,ans;
int num2[100001],num[100001],l[330],cnts[330],b[100001],sum=1;
struct Point{int v,p;}t[100001];
struct Ask{int l,r,p;}Q[100001];
bool operator < (const Point &a,const Point &b){return a.v<b.v;}
bool operator < (const Ask &a,const Ask &b)
{return num2[a.l]!=num2[b.l] ? num2[a.l]<num2[b.l] : a.r<b.r;}
int v[100001],first[100001],next[100001];
int n,es,p,w[100001],w2[100001],L,a[100001],ma[100001],en,lead[100001];
void AddEdge(const int &U,const int &V)
{
v[++es]=V;
next[es]=first[U];
first[U]=es;
}
void dfs(int U)
{
Q[U].l=++L; t[L].v=w[U]; t[L].p=L; lead[L]=w2[U];
for(int i=first[U];i;i=next[i]) dfs(v[i]);
Q[U].r=L; Q[U].p=U;
}
void Val_Make_Block()
{
int sz=sqrt(en); if(!sz) sz=1;
for(;sum*sz<en;++sum)
{
l[sum]=(sum-1)*sz+1; int r=sum*sz;
for(int i=l[sum];i<=r;++i) num[i]=sum;
}
l[sum]=(sum-1)*sz+1;
for(int i=l[sum];i<=en;++i) num[i]=sum;
}
void Mo_Make_Block()
{
int sum=1,sz=sqrt(n); if(!sz) sz=1;
for(;sum*sz<n;++sum)
{
int r=sum*sz;
for(int i=(sum-1)*sz+1;i<=r;++i) num2[i]=sum;
}
for(int i=(sum-1)*sz+1;i<=n;++i) num2[i]=sum;
}
void Insert(const int &x){++b[x]; ++cnts[num[x]]; sumv[num[x]]+=(ll)ma[x];}
void Delete(const int &x){--b[x]; --cnts[num[x]]; sumv[num[x]]-=(ll)ma[x];}
int Query()
{
ll tot=0; int res=0;
for(int i=1;i<=sum;++i)
{
tot+=sumv[i]; res+=cnts[i];
if(tot>m)
{
tot-=sumv[i]; res-=cnts[i];
for(int j=l[i];;++j)
{
tot+=((ll)ma[j]*(ll)b[j]);
res+=b[j];
if(tot>m) return res-(int)((tot-m)/ma[j])-((tot-m)%ma[j]!=0);
}
}
}
return res;
}
int main()
{
scanf("%d%lld",&n,&m);
for(int i=1;i<=n;++i)
{
scanf("%d%d%d",&p,&w[i],&w2[i]);
AddEdge(p,i);
}
dfs(1); sort(t+1,t+n+1);
ma[a[t[1].p]=++en]=t[1].v;
for(int i=2;i<=n;++i)
{
if(t[i].v!=t[i-1].v) ++en;
ma[a[t[i].p]=en]=t[i].v;
}
Val_Make_Block(); Mo_Make_Block();
sort(Q+1,Q+n+1);
for(int i=Q[1].l;i<=Q[1].r;++i) Insert(a[i]);
ans=max(ans,(ll)Query()*(ll)lead[Q[1].l]);
for(int i=2;i<=n;++i)
{
if(Q[i].l<Q[i-1].l) for(int j=Q[i-1].l-1;j>=Q[i].l;--j) Insert(a[j]);
else for(int j=Q[i-1].l;j<Q[i].l;++j) Delete(a[j]);
if(Q[i].r<Q[i-1].r) for(int j=Q[i-1].r;j>Q[i].r;--j) Delete(a[j]);
else for(int j=Q[i-1].r+1;j<=Q[i].r;++j) Insert(a[j]);
ans=max(ans,(ll)Query()*(ll)lead[Q[i].l]);
}
printf("%lld\n",ans);
return 0;
}
【DFS序】【莫队算法】【权值分块】bzoj2809 [Apio2012]dispatching的更多相关文章
- HDU 4358 Boring counting dfs序+莫队算法
题意:N个节点的有根树,每个节点有一个weight.有Q个查询,问在以u为根的子树中,有恰好出现了K次的weight有多少种. 这是第一次写莫队算法,之前也只是偶有耳闻. 看了别人的代码打的,还是贴上 ...
- hdu 4358 Boring counting 离散化+dfs序+莫队算法
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4358 题意:以1为根节点含有N(N <= 1e5)个结点的树,每个节点有一个权值(weight ...
- BZOJ2038: [2009国家集训队]小Z的袜子(hose) -- 莫队算法 ,,分块
2038: [2009国家集训队]小Z的袜子(hose) Time Limit: 20 Sec Memory Limit: 259 MBSubmit: 3577 Solved: 1652[Subm ...
- 莫队算法 sqrt(n)分块思想
在此说一下本渣对莫队算法思想的一些浅薄理解 莫队算法的思想就是对真个区间的分块,然后按照每块来分别进行计算,这样最终的复杂度可以达到n*sqrt(n) 小Z的袜子是一道非常经典的题目.:题目链接htt ...
- hdu 4358 Boring counting dfs序+莫队+离散化
Boring counting Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 98304/98304 K (Java/Others) ...
- CF600E Lomsat gelral (dfs序+莫队)
题面 题解 看到网上写了很多DSU和线段树合并的题解,笔者第一次做也是用的线段树合并,但在原题赛的时候却怕线段树合并调不出来,于是就用了更好想更好调的莫队. 这里笔者就说说莫队怎么做吧. 我们可以通过 ...
- Codeforces 375D - Tree and Queries(dfs序+莫队)
题目链接:http://codeforces.com/contest/351/problem/D 题目大意:n个数,col[i]对应第i个数的颜色,并给你他们之间的树形关系(以1为根),有m次询问,每 ...
- Codeforces 375D Tree and Queries(DFS序+莫队+树状数组)
题目链接 Tree and Queries 题目大意 给出一棵树和每个节点的颜色.每次询问$vj, kj$ 你需要回答在以$vj$为根的子树中满足条件的的颜色数目, 条件:具有该颜色的节点数量至少 ...
- Luogu 1494 - 小Z的袜子 - [莫队算法模板题][分块]
题目链接:https://www.luogu.org/problemnew/show/P1494 题目描述 作为一个生活散漫的人,小Z每天早上都要耗费很久从一堆五颜六色的袜子中找出一双来穿.终于有一天 ...
- 莫队或权值线段树 或主席树 p4137
题目描述 有一个长度为n的数组{a1,a2,…,an}.m次询问,每次询问一个区间内最小没有出现过的自然数. 输入格式 第一行n,m. 第二行为n个数. 从第三行开始,每行一个询问l,r. 输出格式 ...
随机推荐
- HDU1828 Picture 线段树+扫描线模板题
Picture Time Limit: 6000/2000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Sub ...
- offset--BUG
offsetWidth所获取的宽度并不是div的实际宽度,它包括div的width.border等. 在JS函数中,可以通过obj.style.width来获取div的实际宽度,但是这种方式style ...
- OpenStack环境初始化
环境概述 系统:CentOS_7.2_x64_mininal 因配置有限,本次试验使用三台虚拟机,一台控制节点,一台计算节点,一台网络节点,控制机点配置4G内存,2CPU,其他节点都2G内存,一个C ...
- 【FJWC2017】交错和查询 [线段树]
交错和查询 Time Limit: 10 Sec Memory Limit: 256 MB Description 无限循环数字串S由长度为n的循环节s构成.设s为12345(n=5),则数字串S为 ...
- centos 下构建lamp环境
构建准备: 1.配置防火墙,开启80端口.3306端口 vi /etc/sysconfig/iptables -A INPUT -m state --state NEW -m tcp -p tcp - ...
- HDU1003MAX SUM (动态规划求最大子序列的和)
Max Sum Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Sub ...
- 【洛谷 P2480】 [SDOI2010]古代猪文(中国剩余定理,Lucas定理)
题目链接 这题出的有点nb,PKU: Pig Kingdom University , NOIP: National Olympics in Informatic of Pigs... 题意:求\(G ...
- 流程控制 while循环 运算符
具体知识戳这里 可变数据类型:在id不变的情况下,数据类型内部的元素(value)可以改变 如:列表,字典 不可变类型:value改变,id也跟的改变 如:数字.字符.布尔类型 运算符 #算数运算符# ...
- linux驱动基础系列--Linux I2c驱动分析
前言 主要是想对Linux I2c驱动框架有一个整体的把控,因此会忽略协议上的某些细节,同时里面涉及到的一些驱动基础,比如平台驱动.设备模型.sysfs等也不进行详细说明原理,涉及到i2c协议部分也只 ...
- 安全测试===Mysql 注入技巧学习 MySQL注入技巧(1)
默认存在的数据库: mysql 需要root权限读取 information_schema 在5以上的版本中存在 测试是否存在注入方法 假:表示查询是错误的 (MySQL 报错/返回页面与原来不同) ...