ACM-ICPC 2018 焦作赛区网络预赛 E. Jiu Yuan Wants to Eat (树链剖分、线段树)

传送门:https://nanti.jisuanke.com/t/31714

 

题意:

  给一棵树,每个结点有一个值val,初始为0,有4个操作。

  1:从u到v,每个结点更新为 val * x

  2:从u到v,每个结点更新为 val + x

  3:从u到v,每个结点更新为 ~val

  4:输出从u到v路径上的和,对 2^64 取模

 

思路:

  先树剖一下,用线段树维护。然后1、2、4操作都很常规。

  对于操作3,考虑 ~a = 2^64 - 1 - a,然后因为要模 2^64,所以实际上就变为 ~a = - a -1,那么先 * (-1),变为 - a,再 -1,就成了 - a - 1,也就是 ~a。这样的话等于都是1、2、4操作了,然后就变成模板题了。。。

  模 2^64的话ull直接算就可以了。

 

AC代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cstdlib>
#include<utility>
#include<algorithm>
#include<utility>
#include<queue>
#include<vector>
#include<set>
#include<stack>
#include<cmath>
#include<map>
#include<ctime>
#include<functional>
#include<bitset>
#define P pair<int,int>
#define ll long long
#define ull unsigned long long
#define lson id*2,l,mid
#define rson id*2+1,mid+1,r
#define ls id*2
#define rs (id*2+1)
#define Mod(a,b) a<b?a:a%b+b
#define cl0(a) memset(a,0,sizeof(a))
#define cl1(a) memset(a,-1,sizeof(a))
using namespace std;

const ll M = 1e9 + 7;
const ll INF = 1e15;
const int N = 4010;
const double _e = 10e-6;
const int maxn = 1e5 + 10;
const int dx[4] = { 0,0,1,-1 }, dy[4] = { 1,-1,0,0 };
const int _dx[8] = { -1,-1,-1,0,0,1,1,1 }, _dy[8] = { -1,0,1,-1,1,-1,0,1 };

int x, y;
ull val;

int n, m;

int e_max, beg[maxn * 2], nex[maxn * 2], to[maxn * 2];
int cnt, siz[maxn], top[maxn], son[maxn], height[maxn], fa[maxn], nid[maxn], id[maxn];

ull summ[maxn * 4], lazy1[maxn * 4], lazy2[maxn * 4];
void push_up(int id)
{
	summ[id] = summ[ls] + summ[rs];
}
void push_down(int id, int ln, int rn)
{
	if (lazy2[id] != 1) {		
		summ[ls] *= lazy2[id]; summ[rs] *= lazy2[id];
		lazy1[ls] *= lazy2[id]; lazy1[rs] *= lazy2[id];
		lazy2[ls] *= lazy2[id]; lazy2[rs] *= lazy2[id];
		lazy2[id] = 1;
	}
	if (lazy1[id] != 0) {
		summ[ls] += lazy1[id] * ln; summ[rs] += lazy1[id] * rn;
		lazy1[ls] += lazy1[id]; lazy1[rs] += lazy1[id];
		lazy1[id] = 0;
	}	
}
void update(int id, int l, int r, int _l, int _r, ull v,int type)
{
	if (l == _l&&r == _r) {
		if (type == 1) {
			summ[id] *= v;
			lazy1[id] *= v;
			lazy2[id] *= v;
		}
		else if (type == 2) {
			summ[id] += v*(r - l + 1);
			lazy1[id] += v;
		}	
		return;
	}
	int mid = (l + r) / 2;
	push_down(id, mid - l + 1, r - mid);
	if (_r <= mid)
		update(lson, _l, _r, v, type);
	else if (_l > mid)
		update(rson, _l, _r, v, type);
	else {
		update(lson, _l, mid, v, type);
		update(rson, mid + 1, _r, v, type);
	}
	push_up(id);
}
ull query(int id, int l, int r, int _l, int _r)
{
	if (l == _l&&r == _r)
		return summ[id];
	int mid = (l + r) / 2;
	push_down(id, mid - l + 1, r - mid);
	ull ans = 0;
	if (_r <= mid)
		ans += query(lson, _l, _r);
	else if (_l > mid)
		ans += query(rson, _l, _r);
	else
		ans += query(lson, _l, mid) + query(rson, mid + 1, _r);
	push_up(id);
	return ans;
}

void add(int x, int y)
{
	to[++e_max] = y;
	nex[e_max] = beg[x];
	beg[x] = e_max;
}
void dfs1(int u, int father, int depth)
{
	height[u] = depth; fa[u] = father; siz[u] = 1;
	for (int i = beg[u]; ~i; i = nex[i]) {
		int v = to[i];
		if (v != fa[u]) {
			dfs1(v, u, depth + 1);
			siz[u] += siz[v];
			if (son[u] == -1 || siz[v] > siz[son[u]])
				son[u] = v;
		}
	}
}
void dfs2(int u, int t)
{
	top[u] = t;  nid[u] = ++cnt;  id[cnt] = u;
	if (son[u] == -1) return;
	dfs2(son[u], t);
	for (int i = beg[u]; ~i; i = nex[i]) {
		int v = to[i];
		if (v != son[u] && v != fa[u])
			dfs2(v, v);
	}
}
void init()
{
	cnt = 0; e_max = 0;
	memset(son, -1, sizeof(son));  memset(beg, -1, sizeof(beg));
}
ull query_path(int l, int r) {
	ull ans = 0;
	int fl = top[l], fr = top[r];
	while (fl != fr) {
		if (height[fl] >= height[fr]) {
			ans += query(1, 1, n, nid[fl], nid[l]);
			l = fa[fl];
		}
		else {
			ans += query(1, 1, n, nid[fr], nid[r]);
			r = fa[fr];
		}
		fl = top[l], fr = top[r];
	}
	if (nid[l] < nid[r])
		ans += query(1, 1, n, nid[l], nid[r]);
	else
		ans += query(1, 1, n, nid[r], nid[l]);
	return ans;
}
void update_path(int l, int r, ull val, int type)
{
	int fl = top[l], fr = top[r];
	while (fl != fr) {
		if (height[fl] > height[fr]) {
			update(1, 1, n, nid[fl], nid[l], val, type);
			l = fa[fl];
		}
		else {
			update(1, 1, n, nid[fr], nid[r], val, type);
			r = fa[fr];
		}
		fl = top[l], fr = top[r];
	}
	if (nid[l] <= nid[r]) update(1, 1, n, nid[l], nid[r], val, type);
	else update(1, 1, n, nid[r], nid[l], val, type);
}

int main()
{
	while (~scanf("%d", &n)) {
		init(); cl0(summ); cl0(lazy1); 
		fill(lazy2, lazy2 + maxn * 4, 1);
		for (int i = 2; i <= n; i++) {
			scanf("%d", &x);
			add(x, i); add(i, x);
		}
		dfs1(1, 1, 1); dfs2(1, 1);
		scanf("%d", &m);
		int type;
		while (m--) {
			scanf("%d", &type);
			if (type == 1) {
				scanf("%d%d%llu", &x, &y, &val);
				update_path(x, y, val, 1);
			}
			else if (type == 2) {
				scanf("%d%d%llu", &x, &y, &val);
				update_path(x, y, val, 2);
			}
			else if (type == 3) {
				scanf("%d%d", &x, &y);
				update_path(x, y, -1, 1);
				update_path(x, y, -1, 2);
			}
			else {
				scanf("%d%d", &x, &y);
				printf("%llu\n", query_path(x, y));
			}
		}
	}
	return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值