HDU 5957 线段树 附数据生成器

题目大意:

给一个树,然后再随便再多连一条边,形成一个带一个环的树。


一开始,所有树的节点的权重为0


有2个操作。


操作1: 距离结点u距离小于k的所有节点,权重+D

操作2:询问距离节点u距离小于k的所有节点的权重之和。


思路: 先假设题目的图只是一棵树,找一个根节点,BFS一下,dfn[i]表示i节点的BFS时间序列。 可以看出,每个节点的所有儿子的BFS时间序列是连续的,这就可以考虑到线段树来维护了。  并且,用线段树维护还挺好想的。


回到原题,这多一个环,把环弄出来(拓扑排序,最后度为2的点都是环上的)。


环上的点,视为若干个树的根。现在是好多棵树,每棵树的根彼此相连,依旧用线段树来解决,只不过在操作的时候,要多考虑一些东西~细节的话自己考虑一下就行了。


AC CODE:

#include <bits/stdc++.h>
using namespace std;

const int maxn =100000 + 100;
vector<int>g[maxn];
int n;

void init()
{
	scanf("%d", &n);
	for (int i = 0; i <= n; ++ i)
	{
		g[i].clear();
	}
	for (int i = 1; i <= n; ++ i)
	{
		int s, t;
		scanf("%d%d", &s, &t);
		g[s].push_back(t);
		g[t].push_back(s);
	}
}

const int maxnode = 6*maxn;

struct node
{
	int lson, rson;
	int val;//区间权重
	int change;//区间修改值,为0表示没有需要传递的
}tree[maxnode];
int tail;


char input[20];
int du[maxn];
queue<int>q;
int dfn[maxn], dfncnt;
bool vis[maxn];

vector<int>root[maxn];//作为根的节点的朋友节点


void bfs(int arg)
{
	//du[i]==2表示为一个root

	//root[arg]可以知道arg作为根的时候,和哪些点直接连接
	root[arg].clear();
	for (auto will : g[arg])
		if (du[will] == 2)
			root[arg].push_back(will);


	//vis数组,是为了避免找儿子的时候,找到父亲了
	vis[arg] = true;
	q.push(arg);
	while (!q.empty())
	{
		int now = q.front();
		q.pop();
		dfn[now] = ++dfncnt;
		for (auto will : g[now])
		{
			if (du[will] == 2)	continue;
			if (vis[will])	continue;
			q.push(will);
			vis[will] = true;
		}
	}
}

int minson[maxn], maxson[maxn];//最小最大的儿子编号
int mingrandson[maxn], maxgrandson[maxn];//最小最大的孙子编号
int pre[maxn];//父节点

//dfs是找出自己儿子层的数字,和孙子层的数字
void dfs(int now, int fa)
{
	pre[now]=fa;
	minson[now] = mingrandson[now] = 0x7fffffff;
	maxson[now] = maxgrandson[now] = -1;
	for (auto will : g[now])
	{
		if (will == fa)	continue;
		if (du[will] == 2)	continue;
		dfs(will, now);
		if (dfn[will] > maxson[now])	maxson[now] = dfn[will];
		if (dfn[will] < minson[now])	minson[now] = dfn[will];
		if (minson[will] < mingrandson[now])	mingrandson[now] = minson[will];
		if (maxson[will] > maxgrandson[now])	maxgrandson[now] = maxson[will];
	}
}

//#define pr(x)	cout<<#x<<" = "<<x<<" "
//#define prln(x)	cout<<#x<<" = "<<x<<endl
#define pr(x)	x
#define prln(x)	x

void predoit()
{
	memset(du,0,sizeof(du));
	memset(pre,-1,sizeof(pre));
	for (int i = 1; i <= n; ++ i)
	{
		du[i] = g[i].size();
		if (du[i] == 1)	
		{
			//prln(i);
			q.push(i);
		}
	}

	while (!q.empty())
	{
		int now = q.front();
		q.pop();
		for (auto will : g[now])
		{
			du[will]--;
			if (du[will] == 1)
			{
				q.push(will);
			}
		}
	}
	//for (int i = 1; i <= n; ++ i)
	//if (du[i] == 2)	prln(i);

	memset(vis, 0, sizeof(vis));//访问标记
	memset(dfn, 0, sizeof(dfn));//BFS时间戳
	dfncnt = 0;//BFS时间戳记录器

	for (int i = 1; i <= n; ++ i)
		if (du[i] == 2)
		{
			bfs(i);
			dfs(i, -1);
		}
	for (int i = 1; i <= n;++i)
		pr(i),prln(dfn[i]);
}

int ql, qr, qans;
#define LSON tree[o].lson,L, M
#define RSON tree[o].rson, M + 1 , R
#define SELF o,L,R
#define lc tree[o].lson
#define rc tree[o].rson

void build(int o, int L, int R)
{
	tree[o].change = 0;
	tree[o].val = 0;
	if (L== R)
	{
		tree[o].val = 0;
		return ;
	}
	tree[o].lson = ++ tail;
	tree[o].rson = ++ tail;
	int M = L + (R - L) / 2;
	build(LSON);
	build(RSON);
}

void push_down(int o, int L, int R)//向下传递标记
{
	if (tree[o].change && L < R)
	{
		tree[lc].change += tree[o].change;
		tree[rc].change += tree[o].change;
		tree[o].change = 0;
	}
}

void maintain(int o, int L, int R)//把o的儿子的信息,归到o节点
{
	if (L < R)
	{
		int M = L+(R-L)/2;
		tree[o].val = tree[lc].val + tree[rc].val + tree[lc].change * (M-L+1) + tree[rc].change * (R-M);
	}
}

int query(int o, int L, int R)
{
	if (ql <= L && R <= qr)
	{
		return tree[o].val + tree[o].change * (R-L+1);//因为根节点的传递标记一直都在
	}
	push_down(SELF);
	int M = L + (R - L) / 2;
	int ret = 0;
	if (ql <= M)	ret += query(LSON);
	else maintain(LSON);
	if (qr > M)	ret += query(RSON);
	else maintain(RSON);
	maintain(SELF);
	return ret;
}

void update(int o, int L, int R)
{
	if (ql <= L && R <= qr)
	{
		tree[o].change += qans;
		return;
	}else
	{
		push_down(SELF);
		int M = L + (R-L)/2;
		if (ql <= M)	update(LSON);
		else maintain(LSON);
		if (qr > M)	update(RSON);
		else maintain(RSON);
	}
	maintain(SELF);
}

vector<int>sb;

void UD(int u, int k, int d)
{
	//一会儿赋值下QU,然后略改一下参数即可
	qans=d;
	if (!k)
	{
		ql = dfn[u], qr = dfn[u];
		update(0, 1, n);
		pr(ql),prln(qr);
	}
	else if (k==1)
	{
		ql = minson[u],	qr = maxson[u];

		update(0, 1, n);
		pr(ql),prln(qr);

		if (du[u]!=2)//u非根
		{
			ql = qr = dfn[pre[u]];
			update(0, 1, n);
			pr(ql),prln(qr);

			ql = qr = dfn[u];
			update(0, 1, n);
			pr(ql),prln(qr);
		}else
		{
			//u为根
			for (auto will : root[u])
			{
				ql = qr = dfn[will];
				update(0, 1, n);
				pr(ql),prln(qr);
			}
			ql = qr = dfn[u];
			update(0, 1, n);
			pr(ql),prln(qr);
		}
	}
	else//也就是k==2
	{
		ql = minson[u], qr = maxson[u];
		update(0, 1, n);
		pr(ql),prln(qr);

		ql = mingrandson[u], qr = maxgrandson[u];
		update(0, 1, n);
		pr(ql),prln(qr);
		if (du[u]!=2)
		{
			int fa = pre[u];
			ql = minson[fa], qr = maxson[fa];
			update(0, 1, n);
			pr(ql),prln(qr);

			ql = dfn[fa], qr = dfn[fa];
			update(0, 1, n);
			pr(ql),prln(qr);


			if (du[fa] != 2)//依旧没到环上
			{
				fa = pre[fa];
				ql = dfn[fa], qr = dfn[fa];
				update(0, 1, n);
				pr(ql),prln(qr);
			}
			else
			{
				for (auto will : root[fa])
				{
					ql = qr = dfn[will];
					update(0, 1, n);
					pr(ql),prln(qr);
				}
			}
		}
		else
		{
			sb.clear();
			for (auto will : root[u])
			{
				sb.push_back(will);

				ql = minson[will], qr = maxson[will];
				update(0, 1, n);
				pr(ql),prln(qr);
				for (auto x : root[will])
					sb.push_back(x);
			}
			sort(sb.begin(), sb.end());
			sb.erase(unique(sb.begin(),sb.end()),sb.end());
			for (auto will : sb)
			{
				ql = qr = dfn[will];
				update(0, 1, n);
				pr(ql),prln(qr);
			}
		}
	}
}

void QU(int u, int k)
{
	//一会儿赋值下QU,然后略改一下参数即可
	int sum = 0;
	if (!k)
	{
		ql = dfn[u], qr = dfn[u];
		sum += query(0, 1, n);
		pr(ql),prln(qr);
	}
	else if (k==1)
	{
		ql = minson[u],	qr = maxson[u];

		sum += query(0, 1, n);
		pr(ql),prln(qr);

		if (du[u]!=2)//u非根
		{
			ql = qr = dfn[pre[u]];
			sum += query(0, 1, n);
			pr(ql),prln(qr);

			ql= qr = dfn[u];
			sum += query(0, 1, n);
			pr(ql),prln(qr);


		}else
		{
			//u为根
			for (auto will : root[u])
			{
				ql = qr = dfn[will];
				sum += query(0, 1, n);
				pr(ql),prln(qr);
			}
			ql = qr = dfn[u];
			sum += query(0, 1, n);
			pr(ql),prln(qr);
		}
	}
	else//也就是k==2
	{
		ql = minson[u], qr = maxson[u];
		sum += query(0, 1, n);
		pr(ql),prln(qr);

		ql = mingrandson[u], qr = maxgrandson[u];
		sum += query(0, 1, n);
		pr(ql),prln(qr);
		if (du[u]!=2)
		{
			int fa = pre[u];
			ql = minson[fa], qr = maxson[fa];
			sum += query(0, 1, n);
			pr(ql),prln(qr);

			ql = dfn[fa], qr = dfn[fa];
			sum += query(0, 1, n);
			pr(ql),prln(qr);


			if (du[fa] != 2)//依旧没到环上
			{
				fa = pre[fa];
				ql = dfn[fa], qr = dfn[fa];
				sum += query(0, 1, n);
				pr(ql),prln(qr);
			}
			else
			{
				for (auto will : root[fa])
				{
					ql = qr = dfn[will];
					sum += query(0, 1, n);
					pr(ql),prln(qr);
				}
			}
		}
		else
		{
			sb.clear();
			for (auto will : root[u])
			{
				sb.push_back(will);

				ql = minson[will], qr = maxson[will];
				sum += query(0, 1, n);
				pr(ql),prln(qr);
				for (auto x : root[will])
					sb.push_back(x);
			}
			sort(sb.begin(), sb.end());
			sb.erase(unique(sb.begin(),sb.end()),sb.end());
			for (auto will : sb)
			{
				ql = qr = dfn[will];
				sum += query(0, 1, n);
				pr(ql),prln(qr);
			}
		}
	}
	printf("%d\n", sum);
}

void doit()
{
	int T;
	int u, k, d;
	tail=0;
	//root为0
	build(0,1,n);
	//for (int o = 0; o <= tail; ++ o)
	//pr(lc),pr(rc),pr(tree[o].val),prln(tree[o].change);

	scanf("%d", &T);
	while (T--)
	{
		scanf("%s", input);
		if (input[0]=='M')
		{
			scanf("%d%d%d", &u, &k, &d);
			UD(u,k,d);
			for (int o = 0; o <= tail; ++ o)
			pr(o),pr(lc),pr(rc),pr(tree[o].val),prln(tree[o].change);
			prln("\n\n"),prln("\n\n");
		}else
		{
			scanf("%d%d", &u, &k);
			QU(u, k);
			for (int o = 0; o <= tail; ++ o)
			pr(o),pr(lc),pr(rc),pr(tree[o].val),prln(tree[o].change);
			prln("\n\n"),prln("\n\n");
		}
	}
}

int main()
{
	int T;
	scanf("%d", &T);
	while (T--)
	{
		init();
		predoit();
		for (int i = 1; i <= n; ++ i)
			pr(minson[i]),pr(maxson[i]),pr(mingrandson[i]),prln(maxgrandson[i]);
		doit();
		//break;//暂且只测一组数据
	}
	return 0;
}

data maker:

#include <cstdio>
#include <cstring>
#include <vector>
#include <ctime>
#include <iostream>
#include <cstdlib>
using namespace std;

int g[500][500];

int main()
{
	srand(time(0));
	int T = 5;
	cout<<T<<endl;
	while (T--)
	{
		memset(g,0,sizeof(g));
		int n = rand() % 10 + 3;
		cout<<n<<endl;
		for (int i = 2; i <= n; ++ i)
		{
			int a = i, b = rand()%(i-1)+1;
			g[a][b]=g[b][a]=1;
			cout << a <<" " << b<<endl;
		}
		while (1)
		{
			int a = rand()%n+1;
			int b = rand()%n+1;
			if (a!=b && !g[a][b])
			{
				cout<<a<<" "<<b<<endl;
				break;
			}
		}
		int ask=rand()%3+1;
		cout<<ask<<endl;
		while (ask --)
		{
			string a[2];
			a[0]="MODIFY";
			a[1]="QUERY";
			int flag = rand()%2;
			if (flag)
			{
				cout<<a[0]<<" "<<rand()%n+1<<" "<<rand()%2+1<<" "<<rand()%5<<endl;
			}
			else
			{
				cout<<a[1]<<" "<<rand()%n+1<<" "<<rand()%2+1<<endl;
			}
		}
	}
	return 0;
}
/*
2
6
2 1
3 2
4 2
5 1
6 2
4 5
2
QUERY 6 2
MODIFY 6 2 3
7
2 1
3 1
4 1
5 2
6 3
7 2
6 1
2
MODIFY 2 1 4
QUERY 2 2

*/


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值