Problem 1034: Salary Inequity

Time Limits:  10000 MS   Memory Limits:  200000 KB

64-bit interger IO format:  %lld   Java class name:  Main

Description

There is a large company of N employees. With the exception of one employee, everyone has a direct supervisor. The employee with no direct supervisor is indirectly a supervisor of all other employees in the company.
We say that employee X is a subordinate of employee Y if either Y is the direct supervisor of X, or the direct supervisor of X is a subordinate of Y .

One day, the HR department decides that it wants to investigate how much inequity there is in the company with respect to salaries. For a given employee, the inequity of the employee is the difference between the
minimum salary of that employee and all his/her subordinates and the maximum salary of that employee and all his/her subordinates.

HR wants to be able to compute the inequity for any employee quickly. However, this is complicated by the fact that an employee will sometimes give himself/herself, along with all his/her subordinates, a raise.
Can you help?

Input

The first line of your input file contains a number T representing the number of companies you will be analyzing for inequity. T will be at most 20.

For each company, there will be a line containing an integer N, representing the number of employees at the company. Each employee is assigned an ID which is a unique integer from 1 to N. The next line will contain
N − 1 integers. The Kth integer in that line is the ID of the direct supervisor of employee (K + 1). The next line will contain N integers, the Kth integer in this line being the salary of employee K. The next line contains an integer Q, the number of events
that you will need to process. There are two types of events to process - raises and inequity queries. In the event of a raise, the line will start with the letter R followed by the ID of the employee and an integer representing the increase in salary for
that employee and all his/her subordinates. In the event of an inequity query, the line will start with the letter Q followed by the ID of the employee for whom inequity needs to be determined.

2 <= N <= 1,000,000
1 <= Q <= 10,000
For every employee K, the ID of his/her supervisor will be less than K. Initial salaries will

range from 1 to 1,000. No raise will exceed 1,000.

Output

For each inequity query, print the inequity of the employee on its own line.

Sample Input

1
5
1 1 2 2
10 6 8 4 5 7
Q 2
Q 3
R 4 2
Q 2
Q 1
R 2 4
Q 1

Output for Sample Input

2
0
1
5
2

线段树是对于连续的区间操作,但是如果是一棵树,显然是仅符合线段树思想但并不连续,DFS标号构造一个序列,然后再用线段树处理……好题……,输入外挂优化后200MS+,一开始pushdown时左右子树的add忘记加了WA几次…

代码:

#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<sstream>
#include<cstring>
#include<cstdio>
#include<string>
#include<deque>
#include<stack>
#include<cmath>
#include<queue>
#include<set>
#include<map>
using namespace std;
#define INF 0x3f3f3f3f
#define MM(x,y) memset(x,y,sizeof(x))
#define LC(x) (x<<1)
#define RC(x) ((x<<1)+1)
#define MID(x,y) ((x+y)>>1)
typedef pair<int,int> pii;
typedef long long LL;
const double PI=acos(-1.0);
const int N=1000010;
int total,in[N],OUT[N];
int arr[N];
int n;
int ref[N];
int head[N],cnt;
struct info
{
int to;
int pre;
}E[N<<1];
struct seg
{
int l,mid,r;
int maxm,minm,add;
};
seg T[N<<2];
void add(int s,int t)
{
E[cnt].to=t;
E[cnt].pre=head[s];
head[s]=cnt++;
}
void dfs(int now,int fa)
{
in[now]=++total;
ref[total]=now;
for (int i=head[now]; ~i; i=E[i].pre)
{
int v=E[i].to;
if(v!=fa)
dfs(v,now);
}
OUT[now]=total;
}
void init()
{
total=0;
MM(in,0);
MM(OUT,0);
MM(arr,0);
MM(ref,0);
MM(head,-1);
cnt=0;
}
void pushup(int k)
{
T[k].maxm=max(T[LC(k)].maxm,T[RC(k)].maxm);
T[k].minm=min(T[LC(k)].minm,T[RC(k)].minm);
}
void pushdown(int k)
{
if(T[k].add)
{
T[LC(k)].add+=T[k].add;
T[RC(k)].add+=T[k].add;
T[LC(k)].maxm+=T[k].add;
T[RC(k)].maxm+=T[k].add;
T[LC(k)].minm+=T[k].add;
T[RC(k)].minm+=T[k].add;
T[k].add=0;
}
}
void build(int k,int l,int r)
{
T[k].l=l;
T[k].r=r;
T[k].mid=MID(l,r);
T[k].add=T[k].maxm=T[k].minm=0;
if(l==r)
{
T[k].maxm=T[k].minm=arr[ref[l]];//初值的处理
return ;
}
build(LC(k),l,T[k].mid);
build(RC(k),T[k].mid+1,r);
pushup(k);
}
void update(int k,int l,int r,int val)
{
if(r<T[k].l||l>T[k].r)
return ;
if(l<=T[k].l&&r>=T[k].r)
{
T[k].add+=val;
T[k].maxm+=val;
T[k].minm+=val;
}
else
{
pushdown(k);
update(LC(k),l,r,val);
update(RC(k),l,r,val);
pushup(k);
}
}
int mmquery(int k,int l,int r)
{
if(l<=T[k].l&&r>=T[k].r)
return T[k].maxm;
pushdown(k);
if(r<=T[k].mid)
return mmquery(LC(k),l,r);
else if(l>T[k].mid)
return mmquery(RC(k),l,r);
else
return max(mmquery(LC(k),l,T[k].mid),mmquery(RC(k),T[k].mid+1,r));
}
int mnquery(int k,int l,int r)
{
if(l<=T[k].l&&r>=T[k].r)
return T[k].minm;
pushdown(k);
if(r<=T[k].mid)
return mnquery(LC(k),l,r);
else if(l>T[k].mid)
return mnquery(RC(k),l,r);
else
return min(mnquery(LC(k),l,T[k].mid),mnquery(RC(k),T[k].mid+1,r));
}
int Scan()
{
int res=0,ch,flag=0;
if((ch=getchar())=='-')
flag=1;
else if(ch>='0'&&ch<='9')
res=ch-'0';
while((ch=getchar())>='0'&&ch<='9')
res=res*10+ch-'0';
return flag?-res:res;
}
int main(void)
{
int tcase, i, x, q, val;
char ops[3];
scanf("%d",&tcase);
while (tcase--)
{
init();
scanf("%d",&n);
for (i=1; i<n; ++i)
{
x=Scan();
add(x,i+1);
}
for (i=1; i<=n; ++i)
arr[i]=Scan();
dfs(1,-1);
build(1,1,n);
scanf("%d",&q);
while (q--)
{
scanf("%s",ops);
if(ops[0]=='R')
{
scanf("%d%d",&x,&val);
update(1,in[x],OUT[x],val);
}
else
{
scanf("%d",&x);
int m=mmquery(1,in[x],OUT[x]),n=mnquery(1,in[x],OUT[x]);
printf("%d\n",m-n);
}
}
}
return 0;
}

另一种写法:

#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<sstream>
#include<cstring>
#include<cstdio>
#include<string>
#include<deque>
#include<stack>
#include<cmath>
#include<queue>
#include<set>
#include<map>
using namespace std;
#define INF 0x3f3f3f3f
#define MM(x,y) memset(x,y,sizeof(x))
#define LC(x) (x<<1)
#define RC(x) ((x<<1)+1)
#define MID(x,y) ((x+y)>>1)
typedef pair<int,int> pii;
typedef long long LL;
const double PI=acos(-1.0);
const int N=1000010;
struct info
{
int to;
int pre;
}E[N];
int head[N],cnt;
int total,in[N],out[N];
int arr[N];
int n;
struct seg
{
int l,mid,r;
int maxm,minm,add;
};
seg T[N<<2];
void add(int s,int t)
{
E[cnt].to=t;
E[cnt].pre=head[s];
head[s]=cnt++;
}
void dfs(int now,int fa)
{
in[now]=++total;
for (int i=head[now]; ~i; i=E[i].pre)
{
int v=E[i].to;
if(v!=fa)
dfs(v,now);
}
out[now]=total;
}
void init()
{
MM(head,-1);
cnt=0;
total=0;
MM(in,0);
MM(out,0);
MM(arr,0);
}
void pushup(int k)
{
T[k].maxm=max(T[LC(k)].maxm,T[RC(k)].maxm);
T[k].minm=min(T[LC(k)].minm,T[RC(k)].minm);
}
void pushdown(int k)
{
if(!T[k].add)
return ;
T[LC(k)].add+=T[k].add;
T[RC(k)].add+=T[k].add;
T[LC(k)].maxm+=T[k].add;
T[RC(k)].maxm+=T[k].add;
T[LC(k)].minm+=T[k].add;
T[RC(k)].minm+=T[k].add;
T[k].add=0;
}
void build(int k,int l,int r)
{
T[k].l=l;
T[k].r=r;
T[k].mid=MID(l,r);
T[k].add=T[k].maxm=T[k].minm=0;
if(l==r)
return ;
build(LC(k),l,T[k].mid);
build(RC(k),T[k].mid+1,r);
}
void update(int k,int l,int r,int val)
{
if(r<T[k].l||l>T[k].r)
return ;
if(l<=T[k].l&&r>=T[k].r)
{
T[k].add+=val;
T[k].maxm+=val;
T[k].minm+=val;
}
else
{
pushdown(k);
update(LC(k),l,r,val);
update(RC(k),l,r,val);
pushup(k);
}
}
int mmquery(int k,int l,int r)
{
if(l<=T[k].l&&r>=T[k].r)
return T[k].maxm;
pushdown(k);
if(r<=T[k].mid)
return mmquery(LC(k),l,r);
else if(l>T[k].mid)
return mmquery(RC(k),l,r);
else
return max(mmquery(LC(k),l,T[k].mid),mmquery(RC(k),T[k].mid+1,r));
}
int mnquery(int k,int l,int r)
{
if(l<=T[k].l&&r>=T[k].r)
return T[k].minm;
pushdown(k);
if(r<=T[k].mid)
return mnquery(LC(k),l,r);
else if(l>T[k].mid)
return mnquery(RC(k),l,r);
else
return min(mnquery(LC(k),l,T[k].mid),mnquery(RC(k),T[k].mid+1,r));
}
int main(void)
{
int tcase, i, j, x, y, q, val;
char ops[3];
scanf("%d",&tcase);
while (tcase--)
{
init();
scanf("%d",&n);
for (i=1; i<n; ++i)
{
scanf("%d",&x);
y=i+1;
add(x,y);
}
for (i=1; i<=n; ++i)
scanf("%d",&arr[i]);
dfs(1,-1);
build(1,1,n);
for (i=1; i<=n; ++i)
update(1,in[i],in[i],arr[i]);//对于初值的处理
scanf("%d",&q);
while (q--)
{
scanf("%s",ops);
if(ops[0]=='R')
{
scanf("%d%d",&x,&val);
update(1,in[x],out[x],val);
}
else
{
scanf("%d",&x);
int m=mmquery(1,in[x],out[x]),n=mnquery(1,in[x],out[x]);
printf("%d\n",m-n);
}
}
}
return 0;
}

NBOJv2 1034 Salary Inequity(DFS序+线段树区间更新区间(最值)查询)的更多相关文章

  1. POJ.3321 Apple Tree ( DFS序 线段树 单点更新 区间求和)

    POJ.3321 Apple Tree ( DFS序 线段树 单点更新 区间求和) 题意分析 卡卡屋前有一株苹果树,每年秋天,树上长了许多苹果.卡卡很喜欢苹果.树上有N个节点,卡卡给他们编号1到N,根 ...

  2. Educational Codeforces Round 6 E dfs序+线段树

    题意:给出一颗有根树的构造和一开始每个点的颜色 有两种操作 1 : 给定点的子树群体涂色 2 : 求给定点的子树中有多少种颜色 比较容易想到dfs序+线段树去做 dfs序是很久以前看的bilibili ...

  3. 【BZOJ-3252】攻略 DFS序 + 线段树 + 贪心

    3252: 攻略 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 339  Solved: 130[Submit][Status][Discuss] D ...

  4. Codeforces 343D Water Tree(DFS序 + 线段树)

    题目大概说给一棵树,进行以下3个操作:把某结点为根的子树中各个结点值设为1.把某结点以及其各个祖先值设为0.询问某结点的值. 对于第一个操作就是经典的DFS序+线段树了.而对于第二个操作,考虑再维护一 ...

  5. BZOJ2434 [Noi2011]阿狸的打字机(AC自动机 + fail树 + DFS序 + 线段树)

    题目这么说的: 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机.打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P'两个字母.经阿狸研究发现,这个打字机是这样工作的: 输入小 ...

  6. POJ 3321 DFS序+线段树

    单点修改树中某个节点,查询子树的性质.DFS序 子树序列一定在父节点的DFS序列之内,所以可以用线段树维护. 1: /* 2: DFS序 +线段树 3: */ 4:   5: #include < ...

  7. 【XSY2667】摧毁图状树 贪心 堆 DFS序 线段树

    题目大意 给你一棵有根树,有\(n\)个点.还有一个参数\(k\).你每次要删除一条长度为\(k\)(\(k\)个点)的祖先-后代链,问你最少几次删完.现在有\(q\)个询问,每次给你一个\(k\), ...

  8. F - Change FZU - 2277 (DFS序+线段树)

    题目链接: F - Change FZU - 2277 题目大意: 题意: 给定一棵根为1, n个结点的树. 有q个操作,有两种不同的操作 (1) 1 v k x : a[v] += x, a[v ' ...

  9. BZOJ4551[Tjoi2016&Heoi2016]树——dfs序+线段树/树链剖分+线段树

    题目描述 在2016年,佳媛姐姐刚刚学习了树,非常开心.现在他想解决这样一个问题:给定一颗有根树(根为1),有以下 两种操作:1. 标记操作:对某个结点打上标记(在最开始,只有结点1有标记,其他结点均 ...

  10. BZOJ1103 [POI2007]大都市meg dfs序 线段树

    欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ1103 题意概括 一棵树上,一开始所有的边权值为1,我们要支持两种操作: 1. 修改某一条边的权值为 ...

随机推荐

  1. JavaScript设计模式 - 代理模式

    代理模式是为一个对象提供一个代用品或占位符,以便控制对它的访问 代理模式的用处(个人理解):为了保障当前对象的单一职责(相对独立性),而需要创建另一个对象来处理调用当前对象之前的一些逻辑以提高代码的效 ...

  2. mac OS X 安装svn

    因为从10.5版本开始适用Mac OS,SVN一直都是默认安装的软件. 后来发现一个简单的办法. 如果你有安装XCode,只需要在code > Preferences > download ...

  3. XX管理系统案例

    一.登录界面建立登录文件夹Login,在此目录下面建立如下文件:Index.htm:登录页面ValidateCode.cs:生成验证码ProcessVerification.ashx:处理验证码Com ...

  4. 前端代理nproxy

    一.场景/用途 前端代理的用途,相信大家都清楚.应用场景很多,如—— . 将线上的静态资源文件(JS.CSS.图片)替换为本地相应的文件,来调试线上(代码都被压缩过)的问题: . 本地开发过程,当后端 ...

  5. C# Window Form播放音乐的4种方式

    C#播放背景音乐通常有四种方式: 1.播放系统事件声音 2.使用System.Media.SoundPlayer播放wav------------------------仅仅是对波形音乐 3.使用MC ...

  6. 烟大 Contest1024 - 《挑战编程》第一章:入门 Problem A: The 3n + 1 problem(水题)

    Problem A: The 3n + 1 problem Time Limit: 1 Sec  Memory Limit: 64 MBSubmit: 14  Solved: 6[Submit][St ...

  7. GDB调试笔记

    参考资料:GDB调试精粹及使用实例 # 调试实例 #include <iostream> #include <cstring> using namespace std; ][] ...

  8. [原]ASP.NET 数据库访问通用工具

    在工作中,有很多项目已上线后,很多项目的数据库服务器都不会对外开放的,外网想直接访问客户数据库服务器时,可能会出现困难. 这时就需要一个可以查询,更新数据库操作的页面了: 本来用sql语句直接操作数据 ...

  9. JAVA 获取web文件的相对路径

    转自:http://wwwdd2315.blog.163.com/blog/static/66661889201091953350298/ 在JAVA文件中获取该项目的相对路径1.基本概念的理解 绝对 ...

  10. html 音频视频

    <!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8&quo ...