HDU - 4858

题目链接:HDU - 4858


因为边很少,我们可以把非树边单独判断。

然后每个点相邻的点,其实就是一个BFS序。最后把非树边单独求一下。


AC代码:

#pragma GCC optimize("-Ofast","-funroll-all-loops")
#include
//#define int long long
using namespace std;
const int N=1e5+10;
int n,st[N],ed[N],dfn[N],m,f[N],cnt,w[N],sum[N<<2],fa[N];
vector<int> g[N],v[N];
int find(int x){return x==f[x]?x:f[x]=find(f[x]);}
void bfs(){
	queue<int> q; q.push(1); cnt=0; dfn[1]=++cnt;
	while(q.size()){
		int u=q.front(); q.pop();
		for(int to:g[u]) if(!dfn[to]){
			dfn[to]=++cnt; fa[to]=u;
			if(!st[u]) st[u]=dfn[to];
			ed[u]=max(ed[u],dfn[to]);
			q.push(to);
		}
	}
}
#define mid (l+r>>1)
void change(int p,int l,int r,int x,int v){
	if(l==r){sum[p]+=v; return ;}
	if(x<=mid)	change(p<<1,l,mid,x,v);
	else change(p<<1|1,mid+1,r,x,v);
	sum[p]=sum[p<<1]+sum[p<<1|1];
}
int ask(int p,int l,int r,int ql,int qr){
	if(l==ql&&r==qr) return sum[p];
	if(qr<=mid) return ask(p<<1,l,mid,ql,qr);
	else if(ql>mid) return ask(p<<1|1,mid+1,r,ql,qr);
	else return ask(p<<1,l,mid,ql,mid)+ask(p<<1|1,mid+1,r,mid+1,qr);
}
int calc(int x){
	int res=w[fa[x]];
	if(st[x])	res+=ask(1,1,n,st[x],ed[x]);
	for(int to:v[x])	res+=w[to];
	return res;
}
void solve(){
	cin>>n>>m;	memset(sum,0,sizeof sum);
	assert(m>=n-1);
	for(int i=1;i<=n;i++)	
		g[i].clear(),v[i].clear(),f[i]=i,st[i]=ed[i]=dfn[i]=w[i]=fa[i]=0;
	for(int i=1,a,b;i<=m;i++){
		scanf("%d %d",&a,&b);
		int x=find(a),y=find(b);
		if(x!=y)	g[a].push_back(b),g[b].push_back(a),f[x]=y;
		else	v[a].push_back(b),v[b].push_back(a);
	}
	bfs(); int q; cin>>q;
	for(int i=1,op,x,y;i<=q;i++){
		scanf("%d %d",&op,&x);
		if(!op) scanf("%d",&y),w[x]+=y,change(1,1,n,dfn[x],y);
		else printf("%d\n",calc(x));
	}
}
signed main(){
	int T; cin>>T; while(T--) solve();
	return 0;
}

你可能感兴趣的:(线段树,BFS序,HDU)