BZOJ4867 Ynoi2017舌尖上的由乃(dfs序+分块)
容易想到用dfs序转化为序列上的问题。考虑分块,对每块排序,修改时对于整块打上标记,边界暴力重构排序数组,询问时二分答案,这样k=sqrt(nlogn)时取最优复杂度nsqrt(nlogn)logn,离跑过去还差一点。二分答案这一部分看上去很难优化,考虑重构时不那么暴力,将要修改的和不要修改的部分分别从已排序数组中提出来,归并即可,这样k=sqrt(n)logn时取最优复杂度nsqrt(n)logn。尽管加了一些奇怪的卡常然而并没有什么卵用,bzoj上根本过不掉。
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
#define N 100010
char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<''||c>'')) c=getchar();return c;}
int gcd(int n,int m){return m==?n:gcd(m,n%m);}
int read()
{
int x=,f=;char c=getchar();
while (c<''||c>'') {if (c=='-') f=-;c=getchar();}
while (c>=''&&c<='') x=(x<<)+(x<<)+(c^),c=getchar();
return x*f;
}
int n,m,len,p[N],deep[N],dfn[N],id[N],size[N],t,cnt,s;
int block,num,pos[N],L[N],R[N],lazy[N];
struct data{int to,nxt,len;
}edge[N];
struct data2
{
int i,x;
bool operator <(const data2&a) const
{
return x<a.x;
}
}a[N],u[N],v[N],w[N];
struct data3{int i,j,x,op;}Q[N];
void addedge(int x,int y,int z){t++;edge[t].to=y,edge[t].nxt=p[x],edge[t].len=z,p[x]=t;}
void dfs(int k)
{
size[k]=;dfn[k]=++cnt;id[cnt]=k;s=max(s,deep[k]);
for (int i=p[k];i;i=edge[i].nxt)
{
deep[edge[i].to]=deep[k]+edge[i].len;
dfs(edge[i].to);
size[k]+=size[edge[i].to];
}
}
void add(int k,int l,int r,int x)
{
int n=,m=;
for (int i=L[k];i<=R[k];i++)
if (a[i].i>=l&&a[i].i<=r) u[++n].i=a[i].i,deep[id[a[i].i]]+=x,u[n].x=a[i].x+x;
else v[++m]=a[i];
int p=,q=;
for (int i=L[k];i<=R[k];i++)
if (u[p].x<v[q].x&&p<=n||q>m) a[i]=u[p++];
else a[i]=v[q++];
}
int calc(int k,int l,int r)
{
if (pos[l]==pos[r])
{
int s=;
for (int i=l;i<=r;i++)
if (deep[id[i]]+lazy[pos[l]]<=k) s++;
return s;
}
else
{
int s=;
for (int i=pos[l]+;i<pos[r];i++)
s+=upper_bound(a+L[i],a+R[i]+,(data2){,k-lazy[i]})-a-L[i];
for (int i=l;i<=R[pos[l]];i++)
if (deep[id[i]]+lazy[pos[l]]<=k) s++;
for (int i=L[pos[r]];i<=r;i++)
if (deep[id[i]]+lazy[pos[r]]<=k) s++;
return s;
}
}
double complexity(double k,double q){return (m-q)*(n/k+*k)+q*log(s+(m-q)*(len+>>))/log()*(n/k*log(n)/log()+k);}
namespace segmenttree
{
int L[N<<],R[N<<],tree[N<<],lazy[N<<];
void build(int k,int l,int r)
{
L[k]=l,R[k]=r,lazy[k]=;
if (l==r) {tree[k]=deep[id[l]];return;}
int mid=l+r>>;
build(k<<,l,mid);
build(k<<|,mid+,r);
tree[k]=max(tree[k<<],tree[k<<|]);
}
void update(int k,int x){tree[k]+=x,lazy[k]+=x;}
void down(int k){update(k<<,lazy[k]),update(k<<|,lazy[k]),lazy[k]=;}
void add(int k,int l,int r,int x)
{
if (L[k]==l&&R[k]==r) {update(k,x);return;}
if (lazy[k]) down(k);
int mid=L[k]+R[k]>>;
if (r<=mid) add(k<<,l,r,x);
else if (l>mid) add(k<<|,l,r,x);
else add(k<<,l,mid,x),add(k<<|,mid+,r,x);
tree[k]=max(tree[k<<],tree[k<<|]);
}
int query(int k,int l,int r)
{
if (L[k]==l&&R[k]==r) return tree[k];
if (lazy[k]) down(k);
int mid=L[k]+R[k]>>;
if (r<=mid) return query(k<<,l,r);
else if (l>mid) return query(k<<|,l,r);
else return max(query(k<<,l,mid),query(k<<|,mid+,r));
}
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("bzoj4867.in","r",stdin);
freopen("bzoj4867.out","w",stdout);
const char LL[]="%I64d\n";
#else
const char LL[]="%lld\n";
#endif
n=read(),m=read();len=read();
for (int i=;i<=n;i++)
{
int x=read(),y=read();
addedge(x,i,y);
}
dfs();segmenttree::build(,,n);
int qwq=;
for (int i=;i<=m;i++)
{
int op=read(),k=read(),x=read();
if (op==) qwq++;
Q[i].op=op,Q[i].i=dfn[k],Q[i].j=dfn[k]+size[k]-,Q[i].x=x;
}
block=;for (int i=;i<=n;i++) if (complexity(i,qwq)<complexity(block,qwq)) block=i;
num=(n-)/block+;
for (int i=;i<=num;i++)
{
L[i]=(i-)*block+,R[i]=min(n,i*block);
for (int j=L[i];j<=R[i];j++)
pos[j]=i,a[j].i=j,a[j].x=deep[id[j]];
sort(a+L[i],a+R[i]+);
}
for (int i=;i<=m;i++)
{
int l=Q[i].i,r=Q[i].j,x=Q[i].x;
if (Q[i].op==)
{
int left=,right=segmenttree::query(,l,r),ans=-;
while (left<=right)
{
int mid=left+right>>;
if (calc(mid,l,r)>=x) ans=mid,right=mid-;
else left=mid+;
}
printf("%d\n",ans);
}
else
{
segmenttree::add(,l,r,x);
if (pos[l]==pos[r]) add(pos[l],l,r,x);
else
{
for (int i=pos[l]+;i<pos[r];i++) lazy[i]+=x;
add(pos[l],l,R[pos[l]],x),add(pos[r],L[pos[r]],r,x);
}
}
}
return ;
}
BZOJ4867 Ynoi2017舌尖上的由乃(dfs序+分块)的更多相关文章
- BZOJ4867 : [Ynoi2017]舌尖上的由乃
首先通过DFS序将原问题转化为序列上区间加.询问区间kth的问题. 考虑分块,设块大小为$K$,每块维护排序过后的$pair(值,编号)$. 对于修改,整块的部分可以直接打标记,而零碎的两块因为本来有 ...
- BZOJ_4867_[Ynoi2017]舌尖上的由乃_分块+dfs序
BZOJ_4867_[Ynoi2017]舌尖上的由乃_分块+dfs序 Description 由乃为了吃到最传统最纯净的美食,决定亲自开垦一片菜园.现有一片空地,由乃已经规划n个地点准备种上蔬菜.最新 ...
- bzoj 4765 普通计算姬 dfs序 + 分块
题目链接 Description "奋战三星期,造台计算机".小G响应号召,花了三小时造了台普通计算姬.普通计算姬比普通计算机要厉害一些.普通计算机能计算数列区间和,而普通计算姬能 ...
- 2016 ACM/ICPC Asia Regional Dalian Online 1010 Weak Pair dfs序+分块
Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 262144/262144 K (Java/Others)Total Submissio ...
- 【HDU4366】【DFS序+分块】Successor
Problem Description Sean owns a company and he is the BOSS.The other Staff has one Superior.every st ...
- HDU 4366 Successor(dfs序 + 分块)题解
题意:每个人都有一个上司,每个人都有能力值和忠诚值,0是老板,现在给出m个询问,每次询问给出一个x,要求你找到x的所有直系和非直系下属中能力比他高的最忠诚的人是谁 思路:因为树上查询很麻烦,所以我们直 ...
- BZOJ 4765 普通计算姬 dfs序+分块+树状数组+好题!!!
真是道好题...感到灵魂的升华... 按dfs序建树状数组,拿前缀和去求解散块: 按点的标号分块,分成一个个区间,记录区间子树和 的 总和... 具体地,需要记录每个点u修改后,对每一个块i的贡献,记 ...
- HDU - 4366 Successor DFS序 + 分块暴力 or 线段树维护
给定一颗树,每个节点都有忠诚和能力两个参数,随意指定一个节点,要求在它的子树中找一个节点代替它,这个节点要满足能力值大于它,而且是忠诚度最高的那个. 首先,dfs一下,处理出L[i], R[i]表示d ...
- HDU4366 Successor【dfs序 分块】
HDU4366 Successor 题意: 给出一棵根为\(1\)的树,每个点有两个权值\(x,y\),每次询问一个点的子树中\(x\)比这个点的\(x\)大且\(y\)值最大的那个点 题解: 如果以 ...
随机推荐
- RSA加密通信小结(二)-新版本APP与后台通信交互内容修改方案
注1:本次修改分为两步,首先是内容相关的修改,待其完成之后,再进行加密通信项(粗体字备注)修改. 1.新的提交后台的格式包括:data,token(预留字段,暂时后台不校验),userId(已有的不删 ...
- TPO-14 C1 Locate a political book
TPO-14 C1 Locate a political book 第 1 段 1.Listen to a conversation between the student and librarian ...
- leetcode-最长上升子序列LIS
转载原文地址:http://www.cnblogs.com/GodA/p/5180560.html 给定一个无序的整数数组,找到其中最长上升子序列的长度. 示例: 输入: [10,9,2,5,3,7, ...
- 用 splice 函数分别实现 push、pop、shift、unshift 的方法
主要需要注意的是不同方法他们本身返回的值应该是什么,是数组当前的长度,还是取出的元素的值,再在splice函数里面进行相应的return就可以了.具体如下: 用 splice函数实现 push方法 f ...
- Java进阶知识点:更优雅地关闭资源 - try-with-resource
一.背景 我们知道,在Java编程过程中,如果打开了外部资源(文件.数据库连接.网络连接等),我们必须在这些外部资源使用完毕后,手动关闭它们.因为外部资源不由JVM管理,无法享用JVM的垃圾回收机制, ...
- 【Linux 运维】linux系统关机、重启、注销命令
linux 关机.重启.注销命令: 关机命令: shutdown -h now 立刻关机(生产常用) shutdown -h +1 一分钟后关机 ( shutdown -c 可以将 ...
- 网络安全部门的漏洞扫描让你头痛不已么——PHP环境选它就可以了
最近网络安全要求是越来越严,原来PHP编写的程序在XAMPP或者其他环境下总会被某款软件扫出漏洞,进而上级部门就停止了我们服务器的外网出口,然而自从发现了一款安全环境神器UPUPW后,这样的问题就再也 ...
- 普通Java类获取Spring的Bean的方法
普通Java类获取Spring的Bean的方法 在SSH集成的前提下.某些情况我们需要在Action以外的类中来获得Spring所管理的Service对象. 之前我在网上找了好几好久都没有找到合适的方 ...
- Python运行的方式
Python的运行方式多种多样,下面列举几种: 交互式 在命令行中输入python,然后在>>>提示符后面输入Python语句,这里需要注意: 1 语句前面不能有空格,否则会报错 2 ...
- Python-期末练习
1.骑车与走路:我们的校园很大很大很大大大大大……,骑个自行车去办事会很快,比如取个快递了,到其他宿舍楼找个同(nv)学(you)了.但实际上,并非去办任何事情都是骑车快,因为骑车总要找车.开锁.停车 ...