POJ 2763 Housewife Wind LCA转RMQ+时间戳+线段树成段更新

题目来源:POJ 2763 Housewife Wind

题意:给你一棵树 2种操作0 x 求当前点到x的最短路 然后当前的位置为x; 1 i x 将第i条边的权值置为x

思路:树上两点u, v距离为d[u]+d[v]-2*d[LCA(u,v)] 现在d数组是变化的 对应每一条边的变化 他修改的是一个区间 用时间戳处理每个点管辖的区域 然后用线段树修改 线段树的叶子节点村的是根到每一个点的距离 求最近公共祖先没差别 只是堕落用线段树维护d数组

各种错误 4个小时 伤不起

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 200010;
struct edge
{
	int u, v, w, next;
}edges[maxn*2], e[maxn];

int E[maxn*2], H[maxn*2], I[maxn*2], L[maxn], R[maxn];
int dp[maxn*2][40];
int cnt, clock, dfn;
int first[maxn];
int a[maxn<<2];
int b[maxn];
int add[maxn<<2];
int degree[maxn];
int vis[maxn];
void AddEdge(int u, int v, int w)
{
	edges[cnt].u = u;
	edges[cnt].v = v;
	edges[cnt].w = w;
	edges[cnt].next = first[u];
	first[u] = cnt++;
	edges[cnt].u = v;
	edges[cnt].v = u;
	edges[cnt].w = w;
	edges[cnt].next = first[v];
	first[v] = cnt++;
}
void dfs(int u, int fa, int dep)
{
	E[++clock] = u;
	H[clock] = dep;
	I[u] = clock;
	L[u] = ++dfn;
	b[dfn] = u;
	for(int i = first[u]; i != -1; i = edges[i].next)
	{
		int v = edges[i].v;
		if(v == fa)
			continue;
		if(vis[v])
			continue;
		vis[v] = true;
		dfs(v, u, dep+1);
		E[++clock] = u;
		H[clock] = dep;
	}
	R[u] = dfn;
}

void RMQ_init(int n)
{
	for(int i = 1; i <= n; i++)
		dp[i][0] = i;
	for(int j = 1; (1<<j) <= n; j++)
		for(int i = 1; i+(1<<j)-1 <= n; i++)
		{
			if(H[dp[i][j-1]] < H[dp[i+(1<<(j-1))][j-1]])
				dp[i][j] = dp[i][j-1];
			else
				dp[i][j] = dp[i+(1<<(j-1))][j-1];
		}
}
int RMQ(int l, int r)
{
	l = I[l], r = I[r];
	if(l > r)
		swap(l, r);
	int len = r-l+1, k = 0;
	while((1<<k) <= len)
		k++;
	k--;
	if(H[dp[l][k]] < H[dp[r-(1<<k)+1][k]])
		return E[dp[l][k]];
	else
		return E[dp[r-(1<<k)+1][k]];
}
void pushdown(int rt, int l, int r)
{
	int k = (r-l+1);
	if(add[rt])
	{
		a[rt<<1] += add[rt]*(k-(k>>1));
		a[rt<<1|1] += add[rt]*(k>>1);
		add[rt<<1] += add[rt];
		add[rt<<1|1] += add[rt];
		add[rt] = 0;
	}
}

void build(int l, int r, int rt)
{
	a[rt] = 0;
	add[rt] = 0;
	if(l == r)
		return;
	int m = (l + r) >> 1;
	build(l, m, rt<<1);
	build(m+1, r, rt<<1|1);
}

void update(int x, int y, int l, int r, int rt, int num)
{
	if(l == x && r == y)
	{
		a[rt] += (r-l+1)*num;
		add[rt] += num;
		return;
	}
	pushdown(rt, l, r);
	int m = (l + r) >> 1;
	if(y <= m)
		update(x, y, l, m, rt<<1, num);
	else if(x > m)
		update(x, y, m+1, r, rt<<1|1, num);
	else
	{
		update(x, m, l, m, rt<<1, num);
		update(m+1, y, m+1, r, rt<<1|1, num);
	}
	a[rt] = a[rt<<1] + a[rt<<1|1];
}

int query(int x, int l, int r, int rt)
{
	if(l == r)
	{
		return a[rt];
	}
	pushdown(rt, l, r);
	int m = (l + r) >> 1;
	int ans = 0;
	if(x <= m)
		ans = query(x, l, m, rt<<1);
	else
		ans = query(x, m+1, r, rt<<1|1);
	a[rt] = a[rt<<1] + a[rt<<1|1];
	return ans;
}
int main()
{
	int cas = 1;
	int T;
	//scanf("%d", &T);
	int s, to, root, n, q;
	while(scanf("%d %d %d", &n, &q, &s) != EOF)
	{
		memset(vis, 0, sizeof(vis));
		memset(first, -1, sizeof(first));
		memset(degree, 0, sizeof(degree));
		clock = cnt = dfn = 0;

		build(1, n, 1);
		//for(int i = 1; i <= n; i++)
		//	scanf("%d", &b[i]);
		for(int i = 1; i < n; i++)
		{
			int u, v, w;
			scanf("%d %d %d", &u, &v, &w);
			e[i].u = u;
			e[i].v = v;
			e[i].w = w;
			AddEdge(u, v, 0);
			degree[v]++;
		}

		for(int i = 1; i <= n; i++)
			if(!degree[i])
			{
				vis[i] = true;
				dfs(i, -1, 0);
				root = i;
				break;
			}
		RMQ_init(2*n-1);
		//puts("1");
		for(int i = 1; i < n; i++)
		{
			int u = e[i].u;
			int v = e[i].v;
			int w = e[i].w;
			//printf("***%d %d\n", L[v], R[v]);
			if(L[u] < L[v])
				update(L[v], R[v], 1, n, 1, w);
			else
				update(L[u], R[u], 1, n, 1, w);
		}

		while(q--)
		{
			int x;
			scanf("%d", &x);
			if(!x)
			{
				scanf("%d", &to);
				int d1 = query(L[s], 1, n, 1);
				int d2 = query(L[to], 1, n, 1);
				int lca = RMQ(s, to);
				int d3 = query(L[lca], 1, n, 1);
				//printf("***%d %d %d\n", d1, d2, d3);
				printf("%d\n", d1+d2-2*d3);
				//printf("%d\n", dfn);
				s = to;
			}
			else
			{
				int i, w;
				scanf("%d %d", &i, &w);
				int x = w - e[i].w;
				e[i].w = w;
				int v = e[i].v;
				int u = e[i].u;
				if(L[u] < L[v])
					update(L[v], R[v], 1, n, 1, x);
				else
					update(L[u], R[u], 1, n, 1, x);
			}
		}
	}
	return 0;
}

POJ 2763 Housewife Wind LCA转RMQ+时间戳+线段树成段更新

时间: 2024-10-12 22:29:49

POJ 2763 Housewife Wind LCA转RMQ+时间戳+线段树成段更新的相关文章

【POJ】3468 A Simple Problem with Integers ——线段树 成段更新 懒惰标记

A Simple Problem with Integers Time Limit:5000MS   Memory Limit:131072K Case Time Limit:2000MS Description You have N integers, A1, A2, ... , AN. You need to deal with two kinds of operations. One type of operation is to add some given number to each

poj 3468 A Simple Problem with Integers (线段树 成段更新 加值 求和)

题目链接 题意: 只有这两种操作 C a b c" means adding c to each of Aa, Aa+1, ... , Ab. -10000 ≤ c ≤ 10000."Q a b" means querying the sum of Aa, Aa+1, ... , Ab. 分析:自己写的有点麻烦了,写的时候手残+脑残,改了好久. val+lazy*(r-l+1)表示和,如果lazy==0表示当前区间加的值不统一. 1 #include <iostream

poj 3468 A Simple Problem with Integers (线段树成段更新)

A Simple Problem with Integers Time Limit: 5000MS   Memory Limit: 131072K Total Submissions: 77486   Accepted: 23862 Case Time Limit: 2000MS Description You have N integers, A1, A2, ... , AN. You need to deal with two kinds of operations. One type of

poj 3468 A Simple Problem with Integers 【线段树-成段更新】

题目:poj 3468 A Simple Problem with Integers 题意:给出n个数,两种操作 1:l -- r 上的所有值加一个值val 2:求l---r 区间上的和 分析:线段树成段更新,成段求和 树中的每个点设两个变量sum 和 num ,分别保存区间 l--r 的和 和l---r 每个值要加的值 对于更新操作:对于要更新到的区间上面的区间,直接进行操作 加上 (r - l +1)* val .下面的区间标记num += val 对于求和操作,每次进行延迟更新,把num值

POJ - 3468 - A Simple Problem with Integers (线段树 - 成段更新)

题目传送:A Simple Problem with Integers 思路:线段树,成段增减,区间求和,注意延迟标记需要累加,还有会爆int AC代码: #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #include <cmath> #include <queue> #include <stack> #inclu

HDU 3974 Assign the task(dfs时间戳+线段树成段更新)

题意:给定点的上下级关系,规定假设给i分配任务a.那么他的全部下属.都停下手上的工作,開始做a. 操作 T x y 分配x任务y,C x询问x的当前任务: Sample Input 1 5 4 3 3 2 1 3 5 2 5 C 3 T 2 1 C 3 T 3 2 C 3 Sample Output Case #1: -1 1 2 思路: 利用dfs深度优先遍历又一次编号.使一个结点的儿子连续. 然后成段更新. 代码: #include<iostream> #include<cstdio

POJ 2777 Count Color (线段树成段更新+二进制思维)

题目链接:http://poj.org/problem?id=2777 题意是有L个单位长的画板,T种颜色,O个操作.画板初始化为颜色1.操作C讲l到r单位之间的颜色变为c,操作P查询l到r单位之间的颜色有几种. 很明显的线段树成段更新,但是查询却不好弄.经过提醒,发现颜色的种类最多不超过30种,所以我们用二进制的思维解决这个问题,颜色1可以用二进制的1表示,同理,颜色2用二进制的10表示,3用100,....假设有一个区间有颜色2和颜色3,那么区间的值为二进制的110(十进制为6).那我们就把

POJ 2528 Mayor&#39;s posters (hash+线段树成段更新)

题意:有一面墙,被等分为1QW份,一份的宽度为一个单位宽度.现在往墙上贴N张海报,每张海报的宽度是任意的,但是必定是单位宽度的整数倍,且<=1QW.后贴的海报若与先贴的海报有交集,后贴的海报必定会全部或局部覆盖先贴的海报.现在给出每张海报所贴的位置(左端位置和右端位置),问张贴完N张海报后,还能看见多少张海报?(PS:看见一部分也算看到.) 思路:简单的成段更新,但是数据量是1千万,会MT,所以要区间压缩(离散化),保证覆盖的关系不变,离散化的时候有个易错的细节,poj数据水了,这个易错点引用h

POJ训练计划2777_Count Color(线段树/成段更新/区间染色)

解题报告 题意: 对线段染色,询问线段区间的颜色种数. 思路: 本来直接在线段树上染色,lz标记颜色.每次查询的话访问线段树,求出颜色种数.结果超时了,最坏的情况下,染色可以染到叶子节点. 换成存下区间的颜色种数,这样每次查询就不用找到叶子节点了,用按位或来处理颜色种数. #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace