p1651 工资查询 dfs序列化+线段树

版权声明:https://blog.csdn.net/huashuimu2003 https://blog.csdn.net/huashuimu2003/article/details/86320723

题目

描述 Description
fzh当老板了,他的公司一共有N个人,fzh的编号是1,其他人的编号为2…N,他的公司等级极其分明,所以,他的公司的等级关系可以看做是一颗树。
fzh作为老板,是这棵树的root,他直接领导若干下属,他的下属分别会有若干下属。
fzh的员工可以调整他下属的工资,也就是某个员工的下属员工(子树)的工资,工资当然可以增加,也可以减少,并且只要调整,肯定是他的所有下属,他下属的下属当然是他的下属。
fzh并且随时想知道某个员工现在工资是多少?
因为fzh是个蒟蒻所以现在学习OI的dalao,要帮助fzh。
输入格式 Input Format
第一行两个整数:N (1 ≤ N ≤ 500 000), 工人的个数, M (1 ≤ M ≤ 500 000), 工资调整和查询的次数.
接下来N行,每行两个整数,分别表示从1号到N号员工的最原始工资和他的直接领导。注意,这里的第1行是小L,他没有直接领导,所以只有一个整数,表示原始工资。
接下来M行,每行一个命令,命令有两种类型:
1 p A X – 员工A给他的下属调整工资的值为 X (-10 000 ≤ X ≤ 10 000);如果X是正整数,就是涨工资,反之如果是负整数,就是减工资。
2 u A 小L想要查询 员工A的工资
Next N lines contain the information about employees 1, 2, …, N (respectively): starting wage and the identifier of his direct supervisor. Remark: Mirko has no supervisor, so his line will contain only his starting wage.
Next M lines contain one of the following:
1 p A X - employee A increases (or decreases in case of a negative X) wage of all his subordinates by the amount X (-10 000 ≤ X ≤ 10 000);
2.u A - Mirko wants to know the wage of employee A.
输出格式 Output Format
若干行,对于每个u命令,输出相应的员工工资。
样例输入 Sample Input
6 7
5
4 1
3 2
7 3
2 3
3 5
p 3 2
p 2 4
u 3
u 6
p 5 -2
u 6
u 1
样例输出 Sample Output
7
9
7
5
时间限制 Time Limitation
2s
注释 Hint
dfs 序列+线段树
来源 Source
coci2011#3 place

题解

在源神苦苦码代码,而始终不得A掉此题时。我过去查了题解,(好不要脸啊),发现有大佬写到:这就是一道裸的不能再裸的板子题。顿时,我。。。。。。。。。。。。。。(无言以对)!
于是去请教晗神,方才码出AC代码。
好,下面是题解(真正的题解,虽然有人说我总是一句话代码。
1.正如题中注释所说:本题正解为树的dfs序+线段树,我们本以为此题会将两种高深算法结合在一起,搞各种古duliu的操作,然而,并不是,该写什么写什么,(意思就是线段树和dfs序的模板一加,就完成了,当然读入肯定是要改改的。
2.算了,实情是我们用树的dfs序代替了线段树建树的函数,线段树修改与访问都是在树的dfs序上进行操作的。
OK,题解到此结束。(扔下代码就赶紧赶紧逃啊

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=5e5+10;
const int maxm=2e6+10;
char buf[1<<15],*fs,*ft;
inline char getc() { return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++; }
inline int read()
{
    int x=0,f=1;  char ch=getc();
    while (!isdigit(ch)) { if (ch=='-') f=-1; ch=getc(); }
    while (isdigit(ch))  x=(x<<1)+(x<<3)+(ch^48), ch=getc();
    return x*f;
}
inline void put(ll x)
{
	if (!x) { putchar('0'),putchar('\n'); return ; }
	if (x<0) { putchar('-'); x=-x; }
	char stack[20];
	int top=0;
	while (x) { stack[++top]=x%10+'0', x/=10; }
	while (top) putchar(stack[top--]);
	putchar('\n');
}
struct segment_tree
{
	ll val,atag;
}tree[maxm];
int ver[maxn],Next[maxn],head[maxn],len;
inline void add(int x, int y)
{
	ver[++len]=y,Next[len]=head[x],head[x]=len;
}
int st[maxn],en[maxn],name[maxn],money[maxn],tot=0;
void dfs(int now)
{
	st[now]=++tot,name[tot]=now;
	for (int i=head[now];i;i=Next[i])
		dfs(ver[i]);
	en[now]=tot;
}

inline void pushdown(int now)
{
	if (!tree[now].atag) return ;
	tree[now<<1].val+=tree[now].atag;
	tree[now<<1|1].val+=tree[now].atag;
	tree[now<<1].atag+=tree[now].atag;
	tree[now<<1|1].atag+=tree[now].atag;
	tree[now].atag=0;
}

void update(int now,int l,int r,int L,int R,int v)
{
	if (L<=l && r<=R)
	{
		tree[now].atag+=v;
		tree[now].val+=v;
		return;
	}
	else if (l>R || r<L) return ;
	pushdown(now);
	int mid=(l+r)>>1;
	update(now<<1,l,mid,L,R,v);
	update(now<<1|1,mid+1,r,L,R,v);
}

inline int ask(int now,int l,int r,int x)
{
	if (l==r) return tree[now].val;
	pushdown(now);
	int mid=(l+r)>>1;
	if (x<=mid) return ask(now<<1,l,mid,x);
	else return ask(now<<1|1,mid+1,r,x);
}

int main()
{
	int n=read(),m=read();
	money[1]=read();
	for (int i=2;i<=n;++i)
	{
		money[i]=read();
		int x=read();
		add(x,i);
	}
	dfs(1);
	while (m--)
	{
		char opt=getc();
		while (opt!='p' && opt!='u')
			opt=getc();
		int x=read();
		if (opt=='p')
		{
			int y=read();
			update(1,1,n,st[x]+1,en[x],y);
		}
		else
			put(1LL*money[x]+ask(1,1,n,st[x]));
	}
	return 0;
}

另一种风格

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cctype>
#include<algorithm>
#include<cstdlib>
using namespace std;
int read()
{
	int x=0,y=1;	char ch=getchar();
	while (!isdigit(ch)) { if (ch=='-') y=-1; ch=getchar(); }
	while (isdigit(ch)) x=(x<<1)+(x<<3)+ch-'0', ch=getchar();
	return x*y;
}
struct node
{
	int y,ne;
}edge[500010];
int nam[500010],lin[500010],len=0;//nam表示编号为i的是谁,id表示i的编号
inline void addedge(int x,int y)
{
	edge[++len].y=y,edge[len].ne=lin[x],lin[x]=len;
}
int tree[1100010],a[500010],id[500010],en[500010],x,M,n,m,tot=0;
void build()
{
	int mi;
	for (M=1;M<n;M<<=1);
	for (int i=M+1;i<=M+n;i++)
		tree[i]=a[nam[i-M]];
	for (int i=M;i;i--)
		mi=min(tree[i<<1],tree[i<<1|1]),
		tree[i<<1]-=mi,tree[i<<1|1]-=mi,tree[i]+=mi;
}
void update(int l,int r,int v)
{
	int mi;
	for (l+=M-1,r+=M+1;l^r^1;l>>=1,r>>=1)
	{
		if (~l&1)
			tree[l^1]+=v;
		if (r&1)
			tree[r^1]+=v;
		mi=min(tree[r],tree[r^1]);
		tree[r]-=mi,tree[r^1]-=mi,tree[r>>1]+=mi;
		mi=min(tree[l],tree[l^1]);
		tree[l]-=mi,tree[l^1]-=mi,tree[l>>1]+=mi;
	}
	while (l)
	{
		mi=min(tree[l],tree[l^1]);
		tree[l]-=mi,tree[l^1]-=mi,tree[l>>1]+=mi;
		l>>=1;
	}
}		
int query(int x)
{
	int sum=0;
	for (x+=M;x;x>>=1)
		sum+=tree[x];
	return sum;
}
void dfs(int x)
{
	nam[++tot]=x,id[x]=tot;
	for (int i=lin[x];i;i=edge[i].ne)
		dfs(edge[i].y);
	en[id[x]]=tot;
}
int main()
{
	n=read(),m=read();
	a[1]=read();
	int x;
	for (int i=2;i<=n;i++)
		a[i]=read(),x=read(),addedge(x,i);
	dfs(1);
	build();
	while (m--)
	{
		char Q=getchar();
		while (Q!='p'&&Q!='u')	Q=getchar();
		int A=read();
		if (Q=='p')
		{
			x=read();
			update(id[A]+1,en[id[A]],x);
		}
		else printf("%d\n",query(id[A]));
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/huashuimu2003/article/details/86320723