Hdu-5893 List wants to travel(树链剖分)

185 篇文章 0 订阅
50 篇文章 0 订阅

Problem Description
A boy named List who is perfect in English. Now he wants to travel and he is making a plan. But the cost of living in same citie always changes. Now he wants to know how many different kinds of continuous same cost he has to pay for living between two cities. Can you help him? (He is so lazy to do this by himself.)
 

Input
There are multiple cases. The first line contains two positive numbers N and M(N (N<=40000) where N is the amount of cities and M (M<=50000)) is the amount of operations.Then N-1 lines where each line have 3 integers a b and c, representing that there is a bidirectionoal road between city a and city b, and the cost is c.(a != b and c <= 100000). Then there are M lines of operation. For example, "Change a b c" means changing all the costs of the road which are passed by him when he travels from city a to city b to c. "Query a b" means he wants you to tell him how many different kinds of continuous same cost he has to pay traveling from city a to city b.(if a == b, the cost is 0).
 

Output
He insure you that there is exactly one route between every two different cities.
 

Sample Input
  
  
9 3 1 2 2 2 3 1 1 7 2 1 4 2 3 5 2 3 6 1 5 8 2 5 9 3 Query 1 8 Change 2 6 3 Query 1 6
 

Sample Output
  
  
3 2
 

Source
2016 ACM/ICPC Asia Regional Shenyang Online

题意:给一棵边权数,q个操作,每次询问(u,v)路径上有多少段不同边权,或者修改(u,v)上的所有边权。


分析:比赛时从头WA到尾,学树剖时只是草草地熟悉了一下模板,没有深入理解它的原理,所以改这道题时出现了很大的问题,感觉自己还是太浮躁了。

#include<iostream>
#include<string>
#include<algorithm>
#include<cstdlib>
#include<cstdio>
#include<set>
#include<map>
#include<vector>
#include<cstring>
#include<stack>
#include<cmath>
#include<queue>
#define INF 0x3f3f3f3f
#define N 40005
using namespace std;
int dep[N],siz[N],fa[N],id[N],son[N],val[N],top[N],fid[N];
//深度,儿子数量,父亲,新编号,重儿子,权值,所属链头,反编号。 
int T,n,q,num;
vector <int> G[N];
struct Edge
{
	int x,y,val;
} edge[N];
struct Segtree
{
	int l,r,down,lc,rc,ans;
	bool same;
} tree[4*N];
void dfs1(int u,int f,int d)
{
	dep[u] = d;
	siz[u] = 1;
	son[u] = 0;
	fa[u] = f;
	for(int v : G[u])
	 if(v != f)
	 {
	 	 dfs1(v,u,d+1);
	 	 siz[u] += siz[v];
	 	 if(siz[son[u]] < siz[v]) son[u] = v;
	 }
}
void dfs2(int u,int tp)
{
	top[u] = tp;
	id[u] = ++num;
	fid[id[u]] = u;
	if(son[u]) dfs2(son[u],tp);
	for(int v : G[u])
	 if(v != fa[u] && v != son[u]) dfs2(v,v);
}
void push_up(int i)
{
	tree[i].lc = tree[2*i].lc;
	tree[i].rc = tree[2*i+1].rc;
	tree[i].ans = tree[2*i].ans + tree[2*i+1].ans - (tree[2*i].rc == tree[2*i+1].lc);
	tree[i].same = tree[2*i].same && tree[2*i+1].same && (tree[2*i].lc == tree[2*i+1].rc);	
}
void build(int i,int l,int r)
{
	tree[i].l = l;
	tree[i].r = r;
	tree[i].down = 0;
	if(l == r) 
	{
		tree[i].ans = 1;
		tree[i].lc = tree[i].rc = val[fid[l]];
		tree[i].same = true;
		return;
	}
	int mid=(l+r)>>1;
	build(2*i,l,mid);
	build(2*i+1,mid+1,r);
	push_up(i);
}
void Down(int u)
{
	if(!tree[u].down) return;
	tree[2*u].down = tree[2*u+1].down = tree[u].down;
	tree[2*u].ans = tree[2*u+1].ans = 1;
	tree[2*u].lc = tree[2*u].rc = tree[2*u+1].lc = tree[2*u+1].rc = tree[u].down;
	tree[2*u].same = tree[2*u+1].same = true;
	tree[u].down = 0;
}
int query(int i,int x,int y)
{
	int l = tree[i].l,r = tree[i].r;
	if(l == x && r == y) return tree[i].ans;
	Down(i);
	int mid = (l+r)/2;
	if(y <= mid) return query(2*i,x,y);
	else 
	 if(x <= mid) return query(2*i,x,mid) + query(2*i+1,mid+1,y) - (tree[2*i].rc == tree[2*i+1].lc);
	 else return query(2*i+1,x,y);
}
int query_point(int i,int x)
{
	int l = tree[i].l,r = tree[i].r;
	if(tree[i].same) return tree[i].lc;
	Down(i);
	int mid = (l+r)/2;
	if(x <= mid) return query_point(2*i,x);
	else return query_point(2*i+1,x);
}
void deal(int i,int x,int y,int val)
{
	int l = tree[i].l,r = tree[i].r;
	if(l == x && r == y)
	{
		tree[i].down = val;
		tree[i].same = true;
		tree[i].ans = 1;
		tree[i].lc = tree[i].rc = val;
		return;
	}
	Down(i);
	int mid = (l+r)/2;
	if(y <= mid) deal(2*i,x,y,val);
	else 
	 if(x <= mid)
	 {
	 	deal(2*i,x,mid,val);
		deal(2*i+1,mid+1,y,val);
	 }
	 else deal(2*i+1,x,y,val);
	push_up(i);
}
int Yougth_ask(int u,int v)
{
	int tp1 = top[u],tp2 = top[v];
	int ans = 0,pre1 = 0,pre2 = 0; 
	while(tp1 != tp2)
	{
		if(dep[tp1] < dep[tp2])
		{
			swap(tp1,tp2);
			swap(u,v);
			swap(pre1,pre2);
		}
		ans += query(1,id[tp1],id[u]);
		if(pre1) ans -= (query_point(1,id[u]) == pre1);
		pre1 = query_point(1,id[tp1]);
		u = fa[tp1];
		tp1 = top[u]; 
	}
	if(u == v) return (ans - (pre1 == pre2));
	if(dep[u] > dep[v]) 
	{
		swap(u,v);
		swap(pre1,pre2);
	}
	ans += query(1,id[son[u]],id[v]);
	if(pre2) ans -= (query_point(1,id[v]) == pre2);
	if(pre1) ans -= (query_point(1,id[son[u]]) == pre1);
	return ans;
}
void Yougth_deal(int u,int v,int val)
{
	int tp1 = top[u],tp2 = top[v];
	while(tp1 != tp2)
	{
		if(dep[tp1] < dep[tp2])
		{
			swap(tp1,tp2);
			swap(u,v);
		}
		deal(1,id[tp1],id[u],val);
		u = fa[tp1];
		tp1 = top[u]; 
	}
	if(u == v) return;
	if(dep[u] > dep[v]) swap(u,v);
	deal(1,id[son[u]],id[v],val);
}
int main()
{
	while(~scanf("%d%d",&n,&q))
	{
		for(int i = 1;i <= n;i++) G[i].clear();
		for(int i = 1;i < n;i++)
		{
			scanf("%d%d%d",&edge[i].x,&edge[i].y,&edge[i].val);
			edge[i].val++;
			G[edge[i].x].push_back(edge[i].y);
			G[edge[i].y].push_back(edge[i].x);
		}
		num = 0;
		dfs1(1,0,1);
		dfs2(1,1);
		for(int i = 1;i < n;i++)
		 if(dep[edge[i].x] > dep[edge[i].y]) val[edge[i].x] = edge[i].val;
		 else val[edge[i].y] = edge[i].val;
		build(1,1,num);
		char s[20];
		for(int i = 1;i <= q;i++)
		{
			scanf("%s",s);
			if(s[0] == 'Q')
			{ 
				int x,y;
				scanf("%d%d",&x,&y);
				printf("%d\n",Yougth_ask(x,y));
			}
			else 
			{
				int x,y,val;
				scanf("%d%d%d",&x,&y,&val);
				val++;
				Yougth_deal(x,y,val);
			}
		}
	}
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值