bzoj3531

3531: [Sdoi2014]旅行


Description

 S国有N个城市,编号从1到N。城市间用N-1条双向道路连接,满足
从一个城市出发可以到达其它所有城市。每个城市信仰不同的宗教,如飞天面条神教、隐形独角兽教、绝地教都是常见的信仰。为了方便,我们用不同的正整数代表各种宗教,  S国的居民常常旅行。旅行时他们总会走最短路,并且为了避免麻烦,只在信仰和他们相同的城市留宿。当然旅程的终点也是信仰与他相同的城市。S国政府为每个城市标定了不同的旅行评级,旅行者们常会记下途中(包括起点和终点)留宿过的城市的评级总和或最大值。
    在S国的历史上常会发生以下几种事件:
”CC x c”:城市x的居民全体改信了c教;
”CW x w”:城市x的评级调整为w;
”QS x y”:一位旅行者从城市x出发,到城市y,并记下了途中留宿过的城市的评级总和;
”QM x y”:一位旅行者从城市x出发,到城市y,并记下了途中留宿过
的城市的评级最大值。
    由于年代久远,旅行者记下的数字已经遗失了,但记录开始之前每座城市的信仰与评级,还有事件记录本身是完好的。请根据这些信息,还原旅行者记下的数字。    为了方便,我们认为事件之间的间隔足够长,以致在任意一次旅行中,所有城市的评级和信仰保持不变。

Input

    输入的第一行包含整数N,Q依次表示城市数和事件数。
    接下来N行,第i+l行两个整数Wi,Ci依次表示记录开始之前,城市i的
评级和信仰。
    接下来N-1行每行两个整数x,y表示一条双向道路。
    接下来Q行,每行一个操作,格式如上所述。

Output

    对每个QS和QM事件,输出一行,表示旅行者记下的数字。

Sample Input

5 6
3 1
2 3
1 2
3 3
5 1
1 2
1 3
3 4
3 5
QS 1 5
CC 3 1
QS 1 5
CW 3 3
QS 1 5
QM 2 4

Sample Output

8
9
11
3

HINT

N,Q < =10^5    , C < =10^5


 数据保证对所有QS和QM事件,起点和终点城市的信仰相同;在任意时

刻,城市的评级总是不大于10^4的正整数,且宗教值不大于C。


题解:

又用了奇怪的方法。。。
离线处理,先把所有和1宗教有关的操作处理,就是裸的树剖题了,再把所有操作过的点从树剖的线段树中删掉,逐个做每个宗教,就不用动态开点了,但常数会有个2左右,跑的比较慢。



#include <stdio.h>
#include <algorithm>

using namespace std;

const int maxn = 120000;
struct que {
	int kind , x , y , i;
	que *next;
} poolq[maxn*10] , *gq[maxn];
struct tree {
	int v;
	tree *next;
} poolt[maxn*2] , *gt[maxn];
struct node {
	int l , r , s , maxx;
	node *ll , *rr;
} pooln[maxn*8] , *t;
int topq , topn , topt;
int n , q;
int iw[maxn] , ic[maxn];
int used[maxn] , tot;
int ans[maxn];
int dep[maxn] , siz[maxn] , son[maxn] , top[maxn] , w[maxn] , fa[maxn];
int index;
void addque ( int c , int kind , int x , int y , int i ) {
	que *tmp = &poolq[++topq];
	tmp -> kind = kind; tmp -> x = x; tmp -> y = y; tmp -> i = i; tmp -> next = gq[c]; gq[c] = tmp;
}
void add ( int u , int v ) {
	tree *tmp = &poolt[++topt];
	tmp -> v = v; tmp -> next = gt[u]; gt[u] = tmp;
}
void dfs1 ( int i , int from ) {
	siz[i] = 1;
	for ( tree *j = gt[i] ; j ; j = j -> next ) if ( j -> v != from ) {
		dep[j->v] = dep[i] + 1;
		fa[j->v] = i;
		dfs1 ( j -> v , i );
		siz[i] += siz[j->v];
		if ( siz[j->v] > siz[son[i]] ) son[i] = j -> v;
	}
}
void dfs2 ( int i , int from ) {
	w[i] = ++index;
	if ( son[i] ) {
		top[son[i]] = top[i];
		dfs2 ( son[i] , i );
	}
	for ( tree *j = gt[i] ; j ; j = j -> next ) if ( j -> v != from && j -> v != son[i] ) {
		top[j->v] = j -> v;
		dfs2 ( j -> v , i );
	}
}
void buildtree ( node *id , int l , int r ) {
	id -> l = l; id -> r = r;
	if ( l == r ) return ;
	int mid = (l+r)/2;
	id -> ll = &pooln[++topn]; id -> rr = &pooln[++topn];
	buildtree ( id -> ll , l , mid ); buildtree ( id -> rr , mid + 1 , r );
}
void change ( node *id , int x , int y ) {
	if ( id -> l == id -> r ) {
		id -> s = id -> maxx = y;
		return ;
	}
	int mid = (id->l+id->r)/2;
	if ( x <= mid ) change ( id -> ll , x , y );
	else change ( id -> rr , x , y );
	id -> s = id -> ll -> s + id -> rr -> s;
	id -> maxx = max ( id -> ll -> maxx , id -> rr -> maxx );
}
pair<int,int> Union ( pair<int,int> x1 , pair<int,int> x2 ) {
	return make_pair(x1.first+x2.first,max(x1.second,x2.second));
}
pair<int,int> query ( node *id , int l , int r ) {
	if ( id -> l == l && id -> r == r ) return make_pair(id->s,id->maxx);
	int mid = (id->l+id->r)/2;
	if ( r <= mid ) return query ( id -> ll , l , r );
	else {
		if ( l > mid ) return query ( id -> rr , l , r );
		else return Union ( query ( id -> ll , l , mid ) , query ( id -> rr , mid + 1 , r ) );
	}
}
int querytree ( int kind , int x , int y ) {
	int i;
	pair<int,int> ret;
	ret.first = ret.second = 0;
	while ( top[x] != top[y] ) {
		if ( dep[top[x]] < dep[top[y]] ) swap ( x , y );
		ret = Union ( ret , query ( t , w[top[x]] , w[x] ) );
		//printf ( "%d %d %d %d %d\n" , x , y , ret.first , ret.second , top[x] );
		x = fa[top[x]];
	}
	//printf ( "%d\n" , query ( t , w[89] , w[89] ).first );
	if ( dep[x] < dep[y] ) swap ( x , y );
	ret = Union ( ret , query ( t , w[y] , w[x] ) );
	if ( kind == 1 ) return ret.first;
	else return ret.second;
}
void get ( que *id ) {
	if ( !id ) return ;
	get ( id -> next );
	//printf ( "%d %d %d\n" , id -> kind , id -> x , id -> y );
	if ( id -> kind == 1 ) {
		change ( t , w[id -> x] , id -> y );
		used[++tot] = id -> x;
	}
	if ( id -> kind == 2 ) {
		ans[id->i] = querytree ( 1 , id -> x , id -> y );
		//printf ( "s %d %d %d\n" , id -> x , id -> y , ans[id->i] );
	}
	if ( id -> kind == 3 ) {
		ans[id->i] = querytree ( 2 , id -> x , id -> y );
		//printf ( "m %d %d %d\n" , id -> x , id -> y , ans[id->i] );
	}
}
void work () {
	int i , j , u , v , x , y , k;
	char op[10];
	scanf ( "%d%d" , &n , &q );
	for ( i = 1 ; i <= n ; i++ ) {
		scanf ( "%d%d" , &iw[i] , &ic[i] );
		addque ( ic[i] , 1 , i , iw[i] , -1 );
	}
	for ( i = 1 ; i < n ; i++ ) {
		scanf ( "%d%d" , &u , &v );
		add ( u , v ); add ( v , u );
	}
	k = 0;
	for ( i = 1 ; i <= q ; i++ ) {
		scanf ( "%s%d%d" , op + 1 , &x , &y );
		if ( op[2] == 'C' ) {
			addque ( ic[x] , 1 , x , 0 , -1 );
			addque ( y , 1 , x , iw[x] , -1 );
			ic[x] = y;
		}
		if ( op[2] == 'W' ) {
			addque ( ic[x] , 1 , x , y , -1 );
			iw[x] = y;
		}
		if ( op[2] == 'S' ) {
			addque ( ic[x] , 2 , x , y , ++k );
		}
		if ( op[2] == 'M' ) {
			addque ( ic[x] , 3 , x , y , ++k );
		}
	}
	dep[1] = 1;
	dfs1 ( 1 , -1 );
	top[1] = 1;
	dfs2 ( 1 , -1 );
	t = &pooln[++topn];
	buildtree ( t , 1 , n );
	tot = 0;
	for ( i = 1 ; i <= 100000 ; i++ ) {
		//printf ( "%d\n" , i );
		get ( gq[i] );
		for ( j = 1 ; j <= tot ; j++ ) change ( t , w[used[j]] , 0 );
		tot = 0;
	}
	for ( i = 1 ; i <= k ; i++ ) printf ( "%d\n" , ans[i] );
}
int main () {
	//FILE *fpr = freopen ( "bzoj3531.in" , "r" , stdin );
	//FILE *fpw = freopen ( "bzoj3531.out" , "w" , stdout );
	work ();
	return 0;
}



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值