牛客多校第七场 A National Pandemic 树刨

A National Pandemic

题目链接

题目意思

给一颗树
有三种操作:
1 x y 给每个点点权都加上y - dis[x][y] (dis[x][y]是x->y路径上的边数)
2 x 如果x点的点权大于0,就把他变为0.
3 x 查询x的点权。

题解

先看第一种操作
y - dis[x][y] = y - (dep[x] + dep[y] - 2 * dep[lca]) = y - dep[x] - dep[y] + 2 * dep[lca].
怎么实现呢? +2*dep[lca] 可以变为给x的到根节点的路径上num都加2,计算的时候就是到根节点路径上的num和,因为x和y的lca只可能是x到根节点上的值。
所有节点都要加上y-dep[x]值,所以可以有一个sum统计加的这个值。
-dep[y]也就是所有的点的权值都要减去一个他自己的dep,
这个也是全部一起减,所以可以由一个num统计减去的次数。
第二种操作:
要变为0,这个可以开一个delt数组代表减去的值,例如要把x的权值变为0,那么就给delt加上x的权值,之后统计x的点权的时候就直接减去delt就好。
代码:

#include<algorithm>
#include<cstring>
#include <iostream>
#include <cstdio>
#include <queue>
#include <map>
#include <set>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
typedef pair<double,double> pdd;
typedef unsigned long long ull;
typedef set<int>::iterator sit;
#define st first
#define sd second
#define mkp make_pair
#define pb push_back
void tempwj(){freopen("hash.in","r",stdin);freopen("hash.out","w",stdout);}
ll gcd(ll a,ll b){return b == 0 ? a : gcd(b,a % b);}
ll qpow(ll a,ll b,ll mod){a %= mod;ll ans = 1;while(b){if(b & 1)ans = ans * a % mod;a = a * a % mod;b >>= 1;}return ans;}
struct cmp{bool operator()(const pii & a, const pii & b){return a.second < b.second;}};
int lb(int x){return  x & -x;}
//friend bool operator < (Node a,Node b)   重载
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const ll mod = 1e9 + 7;
const int maxn = 1e5+10;
std::vector<int> vv[maxn];
int dep[maxn];
int top[maxn];
int son[maxn];
int fa[maxn];
int num[maxn];
void dfs(int x,int f,int de)
{
	son[x] = 0;
	num[x] = 1;
	fa[x] = f;
	dep[x] = de;
	for (int i = 0; i < vv[x].size(); i ++ )
	{
		int v = vv[x][i];
		if(v == f)
			continue;
		dfs(v,x,de + 1);
		num[x] += num[v];
		if(num[v] > num[son[x]])
			son[x] = v;
	}
}
int p[maxn];
int pos = 1;
void dfs2(int x,int tp)
{
	top[x] = tp;
	p[x] = pos ++ ;
	if(son[x] == 0)
		return;
	dfs2(son[x],tp);
	for(int i = 0; i < vv[x].size(); i ++ )
	{
		int v = vv[x][i];
		if(v == fa[x] || v == son[x])
			continue;
		dfs2(v,v);
	}
}
struct Node
{
	int l,r;
	ll tag,num;
}node[maxn << 2];

void build(int l,int r,int no)
{
	node[no].l = l;
	node[no].r = r;
	node[no].tag = 0;
	node[no].num = 0;
	if(l == r)
	{
		return;
	}
	int mid = l + r >> 1;
	build(l,mid,no<<1);
	build(mid + 1,r,no<<1|1);
}
void xg(int no,ll num)
{
	node[no].num = (node[no].num + 1ll * (node[no].r - node[no].l + 1) * num);
	node[no].tag += num;
	return;
}
void down(int no)
{
	xg(no<<1, node[no].tag);
	xg(no<<1|1, node[no].tag);
	node[no].tag = 0;	
}
void update(int l,int r,int no,int num)
{
	if(node[no].l > r || node[no].r < l)
		return;
	if(node[no].l >= l && node[no].r <= r)
	{
		xg(no,num);
		return;
	}
	if(node[no].tag)
	{
		down(no);
	}
	update(l,r,no<<1,num);
	update(l,r,no<<1|1,num);
	node[no].num = node[no<<1].num + node[no<<1|1].num;
}
ll query(int l,int r,int no)
{
	if(node[no].l > r|| node[no].r < l)
		return 0;
	if(node[no].l >= l && node[no].r <= r)
		return node[no].num;
	if(node[no].tag)
		down(no);
	return query(l,r,no<<1) + query(l,r,no<<1|1);
}

void change(int x,int num)
{
	int k = top[x];
	while(k != 1)
	{
		update(p[k],p[x],1,num);
		x = fa[k];
		k = top[x];
	}
	update(p[k],p[x],1,num);
}

ll getans(int x)
{
	int k = top[x];
	ll ans = 0;
	while(k != 1)
	{
		ans += query(p[k], p[x],1);
		x = fa[k];
		k = top[x];
	}
	ans += query(p[k],p[x],1);
	return ans;
}
ll blnum;
ll blsum;
ll delt[maxn];
ll getsum(int x)
{
	ll ans = getans(x);
	ans += blsum;
	ans -= blnum * dep[x];
	ans -= delt[x];
	return ans;
}
int main()
{
	int T;
	scanf("%d",&T);
	while(T -- )
	{
		blsum = 0;
		blnum = 0;
		int n,m;
		scanf("%d%d",&n,&m);
		for (int i = 1; i <= n; i ++ )
		{
			vv[i].clear();
			delt[i] = 0;
			num[i] = 0;
		}
		for (int i = 1; i < n; i ++ )
		{
			int x,y;
			scanf("%d%d",&x,&y);
			vv[x].pb(y);
			vv[y].pb(x);
		}
		pos = 1;
		dfs(1,0,1);
		dfs2(1,1);
		build(1,n,1);
		while(m -- )
		{
			int f, l, r;
			scanf("%d",&f);
			if(f == 1)
			{
				scanf("%d%d",&l,&r);
				change(l,2);
				blsum += r - dep[l];
				blnum ++ ;
			}
			else if(f == 2)
			{
				int x;
				scanf("%d",&x);
				ll k = getsum(x);
				if(k > 0)
					delt[x] += k;
			}
			else if(f == 3)
			{
				scanf("%d",&l);
				printf("%lld\n",getsum(l));
			}
		}

	}
}


注意初始化、还有第二种操作是大于0才变为0.
害 我好菜~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值