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
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
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;
}