HDU4858 项目管理 其他

匿名 (未验证) 提交于 2019-12-03 00:43:02

原文链接https://www.cnblogs.com/zhouzhendong/p/HDU4858.html

题目传送门 - HDU4858

题意

  给定一个无向图 $n$ 。有 $m$ 条边。

  每一个点有一个权值。

  有 $Q$ 次操作,有两种类型:

题解

  这题本来是个分块题。

  但是,由于 $m\leq n+10$ ,我们就有了一种复杂度正确的简易算法。

  我们先 dfs 跑出原图的一个生成树。于是剩余的边就最多 10 条了。

  我们对于每一个点维护一下除父亲外的权值和,以及单点权值和。

  询问的时候就是第一种信息和父亲的单点权值和加起来。

  修改的时候,首先修改一下自己的单点权值和,然后修改一下父亲的单点权值和,然后暴力修改非树边所指向的点的“除父亲外的权值和”,即可。

代码

#include <bits/stdc++.h> using namespace std; const int N=100025; struct Gragh{ 	static const int M=N*2; 	int cnt,y[M],nxt[M],fst[N]; 	void clear(){ 		cnt=1; 		memset(fst,0,sizeof fst); 	} 	void add(int a,int b){ 		y[++cnt]=b,nxt[cnt]=fst[a],fst[a]=cnt; 	} }g,g2; int T,n,m,Q,fa[N],flag[N],vis[N],v[N],sontot[N]; void dfs(int x,int pre){ 	fa[x]=pre; 	vis[x]=1; 	for (int i=g.fst[x];i;i=g.nxt[i]) 		if (!vis[g.y[i]]){ 			flag[i>>1]=1; 			dfs(g.y[i],x); 		} 		else if (!flag[i>>1]){ 			flag[i>>1]=1; 			g2.add(x,g.y[i]); 			g2.add(g.y[i],x); 		} } int main(){ 	scanf("%d",&T); 	while (T--){ 		scanf("%d%d",&n,&m); 		g.clear(); 		for (int i=1,a,b;i<=m;i++){ 			scanf("%d%d",&a,&b); 			g.add(a,b); 			g.add(b,a); 		} 		memset(fa,0,sizeof fa); 		memset(flag,0,sizeof flag); 		memset(vis,0,sizeof vis); 		memset(sontot,0,sizeof sontot); 		memset(v,0,sizeof v); 		g2.clear(); 		dfs(1,0); 		scanf("%d",&Q); 		while (Q--){ 			int opt,x,y; 			scanf("%d",&opt); 			if (opt==0){ 				scanf("%d%d",&x,&y); 				if (fa[x]) 					sontot[fa[x]]+=y; 				v[x]+=y; 				for (int i=g2.fst[x];i;i=g2.nxt[i]) 					sontot[g2.y[i]]+=y; 			} 			else { 				scanf("%d",&x); 				printf("%d\n",v[fa[x]]+sontot[x]); 			} 		} 	} 	return 0; } 

  

原文:https://www.cnblogs.com/zhouzhendong/p/HDU4858.html

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!