题意

分析

法一:吉司机线段树

这是一个在线的\(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. Eclipse 打包Web项目

    使用插件fatjar Fat jar插件 http://kurucz-grafika.de/fatjar eclipse菜单栏 help->install new software...-> ...

  2. 读写生信流程必备的 Perl 语法

    最早就是写Perl的,后来来到公司转Python,现在又要负责流程了,开始重拾Perl,当然是借鉴别人现有的语法,我再重新组合. 基本语法就不介绍了,参照我之前文章 Perl   模块 use str ...

  3. JDK并发工具之同步控制

    一.synchronized的功能扩展:重入锁(java.util.concurrent.locks.ReentrantLock) 重入锁可以完全替代synchronized关键字.在JDK 5.0的 ...

  4. 3-20 标准库:find库; 学习编程语言3节课(大多是旧识,全*栈)3-21 面向对象. Percent Strings; 元编程和Rails的相互理解

    Find The Find module supports the top-down traversal of a set of file paths.(一系列文件的路径的遍历) find(*path ...

  5. Fair CodeForces - 987D (bfs)

    链接 大意:给定无向图边权均为1, 每个节点有一种货物, 对于每个节点, 求出拿到$s$种不同货物的最短距离 (每种货物独立计算,并且不用返回) 因为$s$较小, 直接枚举每种货物即可 所以问题就转化 ...

  6. zzuli303(奇葩26进制转换)

    序号互换 时间限制:1000 ms  |  内存限制:65535 KB 难度:2   描述 Dr.Kong设计了一个聪明的机器人卡多,卡多会对电子表格中的单元格坐标快速计算出来.单元格的行坐标是由数字 ...

  7. zzuli 1432(二进制特点)

      1432: 背包again Time Limit: 1 Sec  Memory Limit: 128 MBSubmit: 222  Solved: 65 SubmitStatusWeb Board ...

  8. Silverlight 5 Developer Rumtime

    因为更新了Silverlight SDK,所以也要更新相应的Silverlight开发运行时. Silverlight 5 Developer Rumtime (32bit): http://go.m ...

  9. POJ 2896 另解暴力

    就是简单的用strstr函数对字符串进行处理. 另解:暴力(就是用strstr函数对字符串进行处理)另解:暴力(普通的字符串处理 .关键是strstr函数): #include<stdio.h& ...

  10. httpclient http状态管理

    HTTP状态管理 最初,Htt被设计成一个无状态的面向请求响应的协议,所以它不能再逻辑相关的http请求/响应中保持状态会话. 由于越来越多的系统使用http协议,其中包括http从来没有想支持的系统 ...