题意

分析

法一:吉司机线段树

这是一个在线的\(O( n + q \cdot \log^2 n)\)做法。

考虑维护节点到根的权值前缀和cost,那么查询的时候区间减去子树根节点的cost就是价值。

然后由于子树dfs序连续,转化成线段树的区间查询。

对区间查询,分为4种情况:

  1. 最大值都无价值,答案为0
  2. 最大值有价值,但次大值以后都无价值,那么答案就是最大值价值乘以最大值个数
  3. 最小值有价值,那么所有的都有价值,答案是sum-cost*区间长
  4. 以上条件都不满足,递归处理
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<ctime>
#include<iostream>
#include<string>
#include<vector>
#include<list>
#include<deque>
#include<stack>
#include<queue>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<complex>
#pragma GCC optimize ("O0")
using namespace std;
template<class T> inline T read(T&x)
{
T data=0;
int w=1;
char ch=getchar();
while(!isdigit(ch))
{
if(ch=='-')
w=-1;
ch=getchar();
}
while(isdigit(ch))
data=10*data+ch-'0',ch=getchar();
return x=data*w;
}
typedef long long ll;
const int INF=0x7fffffff; const int MAXN=1e5+7; struct Edge
{
int nx,to,w;
}E[MAXN];
int head[MAXN],ecnt; void addedge(int x,int y,int w)
{
E[++ecnt].to=y,E[ecnt].w=w;
E[ecnt].nx=head[x],head[x]=ecnt;
} int dfn[MAXN],siz[MAXN],cost[MAXN];
int idx[MAXN],clk; void dfs(int x)
{
// cerr<<"dfsing "<<x<<endl;
dfn[x]=++clk;
siz[x]=1;
idx[clk]=x;
for(int i=head[x];i;i=E[i].nx)
{
int y=E[i].to,w=E[i].w;
cost[y]=cost[x]+w;
dfs(y);
siz[x]+=siz[y];
}
} int ql,qr,c,k;
struct SegTree
{
ll sumv[MAXN<<2];
int maxv[MAXN<<2],num[MAXN<<2],secv[MAXN<<2];
int minv[MAXN<<2];
#define lson (now<<1)
#define rson (now<<1|1)
void pushup(int now)
{
sumv[now]=sumv[lson]+sumv[rson];
maxv[now]=max(maxv[lson],maxv[rson]);
minv[now]=min(minv[lson],minv[rson]);
if(maxv[lson]==maxv[rson])
{
num[now]=num[lson]+num[rson];
secv[now]=max(secv[lson],secv[rson]);
}
else
{
num[now]=maxv[lson]>maxv[rson]?num[lson]:num[rson];
secv[now]=max(secv[lson],secv[rson]);
secv[now]=max(secv[now],min(maxv[lson],maxv[rson]));
}
} void build(int now,int l,int r)
{
if(l==r)
{
sumv[now]=cost[idx[l]];
maxv[now]=minv[now]=sumv[now];
num[now]=1;
secv[now]=-1;
return;
}
int mid=(l+r)>>1;
build(lson,l,mid);
build(rson,mid+1,r);
pushup(now);
} ll query(int now,int l,int r)
{
if(ql<=l&&r<=qr)
{
if(maxv[now]<c+k)
return 0;
if(secv[now]<c+k)
return (ll)(maxv[now]-c)*num[now];
if(minv[now]>=c+k)
return sumv[now]-(ll)c*(r-l+1);
}
int mid=(l+r)>>1;
ll ans=0;
if(ql<=mid)
ans+=query(lson,l,mid);
if(qr>=mid+1)
ans+=query(rson,mid+1,r);
return ans;
}
}T; int main()
{
freopen("forging.in","r",stdin);
freopen("forging.out","w",stdout);
int n;
read(n);
for(int i=2;i<=n;++i) // edit 1:root has no father
{
static int fa,w;
read(fa);read(w);
addedge(fa,i,w);
}
dfs(1);
T.build(1,1,n);
int q;
read(q);
while(q--)
{
static int u;
read(u);read(k);
ql=dfn[u],qr=dfn[u]+siz[u]-1,c=cost[u];
printf("%lld\n",T.query(1,1,n));
}
// fclose(stdin);
// fclose(stdout);
return 0;
}

法二:平衡树

题意是给定一棵带边权的有根树,每次询问一个点u的子树内与其距离至少是k的点到u的距离之和。

容易想到如果我们能维护出每个点子树内点到其距离的有序表,询问将十分简单。我们将询问离线挂在每个点上,从下向上用平衡树维护每个点的子树内距离,合并时启发式合并。

\(O(n \log^2 n + q \log n)\)

#include <bits/stdc++.h>

using LL = long long;

const int MAXN = 1e5 + 5;

struct SplayTree {
struct Node {
Node *fa, *ch[2];
LL sum, tag, val;
int size; Node(LL _val): sum(_val), val(_val) {
fa = ch[0] = ch[1] = 0;
tag = 0;
size = 1;
} void Add(LL w) {
val += w;
sum += w * size;
tag += w;
} void Down() {
for (int i = 0; i < 2; ++i) if (ch[i])
ch[i]->Add(tag);
tag = 0;
} void DownR() {
if (fa) fa->DownR();
Down();
} void Update() {
sum = val;
size = 1;
for (int i = 0; i < 2; ++i) if (ch[i]) {
sum += ch[i]->sum;
size += ch[i]->size;
}
} int Which() {
return this == fa->ch[1];
}
} *root; SplayTree() = default; void Rotate(Node *k) {
Node *p = k->fa;
int l = k->Which(), r = l ^ 1; k->fa = p->fa;
if (p->fa) p->fa->ch[p->Which()] = k; p->ch[l] = k->ch[r];
if (k->ch[r]) k->ch[r]->fa = p; k->ch[r] = p;
p->fa = k; p->Update();
k->Update();
} void Splay(Node *k, Node *aim_fa = 0) {
k->DownR(); while (k->fa != aim_fa) {
Node *p = k->fa;
if (p->fa != aim_fa) {
if (k->Which() ^ p->Which()) Rotate(k);
else Rotate(p);
}
Rotate(k);
} if (!aim_fa) root = k;
} void Insert(LL val, Node *&k, Node *fa = 0) {
if (!k) {
k = new Node(val);
k->fa = fa;
Splay(k);
return;
}
k->Down();
Insert(val, k->ch[val > k->val], k);
} void Add(LL val) {
root->Add(val);
} void Traverse(std::vector<LL> &vec, Node *k) {
if (!k) return;
k->Down();
Traverse(vec, k->ch[0]);
vec.push_back(k->val);
Traverse(vec, k->ch[1]);
} void Delete(Node *&k) {
if (!k) return;
for (int i = 0; i < 2; ++i) Delete(k->ch[i]);
delete k; k = 0;
} void Merge(SplayTree &oth) {
if (root->size < oth.root->size) std::swap(root, oth.root); // std::cerr << root->size << " " << oth.root->size << std::endl; std::vector<LL> list;
oth.Traverse(list, oth.root);
oth.Delete(oth.root);
for (LL i: list)
Insert(i, root);
} LL Query(LL val) {
Node *k = root, *p = 0;
while (k) {
k->Down();
if (k->val < val) {
p = k;
k = k->ch[1];
} else {
k = k->ch[0];
}
}
if (!p) return root->sum;
Splay(p);
if (!root->ch[1]) {
return 0;
} else {
return root->ch[1]->sum;
}
}
} splay[MAXN]; int n, q;
std::vector<int> G[MAXN];
int fa[MAXN], w[MAXN]; std::vector<std::pair<int, int>> qry[MAXN]; LL ans[MAXN]; void DFS(int now) {
splay[now].Insert(0, splay[now].root);
for (int to: G[now]) {
DFS(to); splay[to].Add(w[to]);
splay[now].Merge(splay[to]);
} for (auto i: qry[now]) {
int k = i.first, idx = i.second; ans[idx] = splay[now].Query(k);
}
} void Main() {
#ifndef LOCAL
freopen("forging.in", "r", stdin);
freopen("forging.out", "w", stdout);
#endif scanf("%d", &n);
for (int i = 2; i <= n; ++i) {
scanf("%d%d", fa + i, w + i);
G[fa[i]].push_back(i);
} scanf("%d", &q);
for (int i = 1; i <= q; ++i) {
static int u, k; scanf("%d%d", &u, &k);
qry[u].emplace_back(k, i);
} DFS(1); for (int i = 1; i <= q; ++i)
printf("%lld\n", ans[i]);
} register char *_sp __asm__("rsp"); int main() {
const int size = 32 << 20;
static char *sys, *mine(new char[size] + size - 4096);
sys = _sp; _sp = mine; Main(); _sp = sys; return 0;
}

test20180922 打铁的匠的更多相关文章

  1. NOIP模拟赛 打铁的匠 题解

    [问题描述] Mark Douglas是一名优秀的锻造师.与他优秀的锻造水平不相符,他非常穷,以至于很多好刀都因为缺少素材缺少资金无法打造. Mark把他有能力锻造的所有n种刀建成了一棵锻造树,除了第 ...

  2. NOIp2018集训test-9-22(am/pm) (联考三day1/day2)

    szzq学长出的题,先orz一下. day1 倾斜的线 做过差不多的题,写在我自己的博客里,我却忘得一干二净,反而李巨记得清清楚楚我写了的. 题目就是要最小化这个东西 $|\frac{y_i-y_j} ...

  3. BZOJ 1296: [SCOI2009]粉刷匠 分组DP

    1296: [SCOI2009]粉刷匠 Description windy有 N 条木板需要被粉刷. 每条木板被分为 M 个格子. 每个格子要被刷成红色或蓝色. windy每次粉刷,只能选择一条木板上 ...

  4. cojs 疯狂的粉刷匠 疯狂的斐波那契 题解报告

    疯狂的斐波那契 学习了一些奇怪的东西之后出的题目 最外层要模p是显然的,然而内层并不能模p 那么模什么呢,显然是模斐波那契的循环节 那么我们可以一层层的求出每层的斐波那契循环节 之后在从内向外用矩阵乘 ...

  5. 2014.7.8模拟赛【笨笨当粉刷匠】|bzoj1296 [SCOI]粉刷匠

    笨笨太好玩了,农田荒芜了,彩奖用光了,笨笨只好到处找工作,笨笨找到了一份粉刷匠的工作.笨笨有n条木板需要被粉刷.每条木板被分成m个格子,每个格子要被刷成红色或蓝色.笨笨每次粉刷,只能选择一条木板上一段 ...

  6. xdu_RainAndBow 鞍山打铁记

    我们作为弱校xdu的七队(大四一支,大三四支,大二俩),本来都没指望今年可以出去,结果运气不错,学校得到几个激动名额, 于是我们激动地成功申请到了鞍山站的名额,嗯...可以出去旅游了. 不过我们毕竟太 ...

  7. BZOJ 1296: [SCOI2009]粉刷匠( dp )

    dp[ i ][ j ] = max( dp[ i - 1 ][ k ] + w[ i ][ j - k ] )  ( 0 <= k <= j ) 表示前 i 行用了 j 次粉刷的机会能正 ...

  8. 使用.NET开发AutoCAD——设计师不做画图匠(一)

    (一)前言--如何避免加班那些事 我是谁?我是一名工程设计师,有点"不务正业",在工作之余长期从事软件开发工作,开发了公路铁路行业广泛应用的设计软件.说正题之前,聊聊加班那些事.话 ...

  9. 泥瓦匠想做一个与众不同的技术"匠"

    点击蓝字,关注泥瓦匠 本文阅读大约 3 分钟.感谢阅读 喝了最后一口百事可乐,想到它的 slogan:新一代的选择.新一代的选择,每个人选择不同,人生道路历程也不同.就像我刚毕业的时候,毕业选择不一样 ...

随机推荐

  1. English trip -- VC(情景课) 6 D

    Read 阅读 Teresa‘s Day Treesa's  is busy today. he meeting with her friend Joan is at 10:00. Her docto ...

  2. Vue.js Cookbook: 添加实例属性; 👍 axios(4万➕✨)访问API; filters过滤器;

    add instance properties //加上$,防止和已经定义的data,method, computed的名字重复,导致被覆写.//可以自定义添加其他符号. Vue.prototype. ...

  3. AsyncTask用法和异步加载图片

    AsyncTask:是Android提供的轻量级的异步类,可以直接继承AsyncTask,在类中实现异步操作,并提供接口反馈当前异步执行的程度(可以通过接口实现UI进度更新),最后反馈执行的结果给UI ...

  4. (转)理解TIME_WAIT,彻底弄清解决TCP: time wait bucket table overflow

    转载自http://blog.51cto.com/benpaozhe/1767612: 一直对这个问题知其然而不知其所以然,这些日子再次碰到,看了很多的资料,彻底解决一下,呵呵,先上个图,所有理解围绕 ...

  5. 为用户管理连接 Confluence 6 到 Jira 应用程序

    请注意,在使用这个功能的时候,你的 Jira 应用许可证数量和 Confluence 的许可证数量不需要完全等同.例如,你可以通过 Jira 管理一个 50 个用户的 Confluence 许可证,尽 ...

  6. Confluence 6 导入 Active Directory 服务器证书 - UNIX

    为了让你的应用服务器能够信任你的目录服务器.你目录服务器上导出的证书需要导入到你应用服务器的 Java 运行环境中.JDK 存储了信任的证书,这个存储信任证书的文件称为一个 keystore.默认的 ...

  7. 『Scrapy』全流程爬虫demo

    建立好的爬虫工程如下: item.py 它用来存储解析后的响应文件: # -*- coding: utf-8 -*- # Define here the models for your scraped ...

  8. python-day37--协程

    一. 协程介绍 单线程下实现并发,提升运行效率, 1.自己控制切换,保存状态 2.遇到I/O切         (单纯的CPU切没意义,只有在遇到I/O的时候切才有效率) 一句话说明什么是线程:协程是 ...

  9. Get和Load的区别----hibernate

    Get和Load的区别

  10. python 使用yield进行数据的流式处理

    demo:从文件中取包含字符“a”的5行数据做一次批处理!!! # coding: utf-8 import time def cat(f): for line in f: yield line de ...