说在前面
me发现me的代码简直冗杂的一比…
虽然跑得快,但是写起来简直要死人
题目
题目大意
为什么这题是权限题啊woc,me懒得概括题意啊喂!
给出一棵N个节点的树。除了树边之外,这棵树上的某两个点还可能出现传送门。初始状态时,树上已经有一些传送门。
现在需要支持三种操作:
1. 添加一个链接(u,v)的传送门
2. 崩塌一个链接(u,v)的传送门(保证存在)
3. 询问从u到v且不经过「原树(没有传送门)上u到v路径中任意一条边」的路径有多少条
数据范围:节点数100000,操作总数50000,初始传送门50000
输入输出格式
输入格式:
第一行一个整数N,表示节点个数
接下来N-1行,每行一个二元组(u,v)描述一条树边
接下来一行一个整数M,表示初始传送门个数
接下来M行,每行一个二元组(u,v)描述一个传送门
接下来一行一个整数Q,表示操作个数
接下来Q行,每行一个三元组(opt,u,v)描述一个操作,opt与题面对应
输出格式:
对于每个询问,输出一行表示答案
解法
这道题的原题面有巨大的理解歧义,差评
首先把样例图画出来,然后发现自己读懂了题意
可以发现,在一个询问中,一个传送门最多只会贡献1的答案,当且仅u和v都在这个传送门和树边形成的环上
也就是原树上,u到v的路径被传送门端点间的路径完全包含,然后这道题就和BZOJ4009一样了
即可以将该题转化为:支持插入点和删除点,询问一个矩形内的点数
把每个矩形询问 差分为 四个前缀和询问,然后直接用CDQ三维偏序解决即可。
注意这里的三位偏序是不严格的,询问点和插入点可能重合,一点小改动即可处理
下面是自带小常数的代码
/**************************************************************
Problem: 4285
User: Izumihanako
Language: C++
Result: Accepted
Time:6900 ms
Memory:42352 kb
****************************************************************/
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std ;
int N , M , Q , tp , head[100005] , ans[50005] , ocnt , qcnt , Qcnt ;
struct Path{
int pre , to ;
}p[200005] ;
struct queries{
int x , y , k , id , tim ;
}q[400005] , Lq[400005] , Rq[400005] ;
struct options{
int x , y , delta , tim ;
}o[100005] , Lo[100005] , Ro[100005] ;
struct BIT{
int b[100005] ;
void Modify( int x , int delta ){
for( ; x <= N ; x += x&-x )
b[x] += delta ;
}
int Query( int x ){
int rt = 0 ;
for( ; x ; x -= x&-x )
rt += b[x] ;
return rt ;
}
} B ;
void setMat( int x1 , int x2 , int y1 , int y2 , int i ){
q[++qcnt] = ( queries ){ x2 , y2 , 1 , Qcnt , i } ;
q[++qcnt] = ( queries ){ x2 , y1-1 , -1 , Qcnt , i } ;
q[++qcnt] = ( queries ){ x1-1 , y2 , -1 , Qcnt , i } ;
q[++qcnt] = ( queries ){ x1-1 , y1-1 , 1 , Qcnt , i } ;
}
void In( int t1 , int t2 ){
p[++tp].pre = head[t1] ;
p[ head[t1] = tp ].to = t2 ;
}
int dep[100005] , fa[17][100005] , dfs_c , in[100005] , out[100005] ;
void dfs( int u ){
in[u] = ++dfs_c ;
for( int i = head[u] ; i ; i = p[i].pre ){
int v = p[i].to ;
if( v == fa[0][u] ) continue ;
dep[v] = dep[u] + 1 ;
fa[0][v] = u , dfs( v ) ;
} out[u] = dfs_c ;
}
int getW( int u , int v ){
for( int i = 16 ; i >= 0 ; i -- )
if( dep[ fa[i][v] ] > dep[u] ) v = fa[i][v] ;
return v ;
}
void preWork(){
fa[0][1] = 1 , dfs( 1 ) ;
for( int i = 1 ; i <= 16 ; i ++ )
for( int j = 1 ; j <= N ; j ++ )
fa[i][j] = fa[i-1][ fa[i-1][j] ] ;
scanf( "%d" , &M ) ;
for( int i = 1 , u , v ; i <= M ; i ++ ){
scanf( "%d%d" , &u , &v ) ;
if( in[u] > in[v] ) swap( u , v ) ;
o[++ocnt] = ( options ){ in[u] , in[v] , 1 , 0 } ;
}
scanf( "%d" , &Q ) ;
for( int i = 1 , ct , u , v ; i <= Q ; i ++ ){
scanf( "%d%d%d" , &ct , &u , &v ) ;
if( in[u] > in[v] ) swap( u , v ) ;
if( ct == 1 ) o[++ocnt] = ( options ){ in[u] , in[v] , 1 , i } ;
if( ct == 2 ) o[++ocnt] = ( options ){ in[u] , in[v] ,-1 , i } ;
if( ct == 3 ){
Qcnt ++ ;
if( in[u] < in[v] && out[v] <= out[u] ){
int w = getW( u , v ) ;
setMat( 1 , in[w] - 1 , in[v] , out[v] , i ) ;
if( out[w] < N ) setMat( in[v] , out[v] , out[w] + 1 , N , i ) ;
} else setMat( in[u] , out[u] , in[v] , out[v] , i ) ;
}
}
}
void CDQ( int oL , int oR , int qL , int qR , int xL , int xR ){
int mid = ( xL + xR ) >> 1 , Lqt = 0 , Rqt = 0 , Lot = 0 , Rot = 0 , pt1 , pt2 ;
for( pt1 = oL , pt2 = qL ; pt2 <= qR ; pt2 ++ ){
while( pt1 <= oR && o[pt1].tim <= q[pt2].tim ){
if( o[pt1].x <= mid ){
B.Modify( o[pt1].y , o[pt1].delta ) ;
Lo[++Lot] = o[pt1++] ;
} else Ro[++Rot] = o[pt1++] ;
}
if( q[pt2].x > mid || xL == xR ){
ans[ q[pt2].id ] += q[pt2].k * B.Query( q[pt2].y ) ;
Rq[++Rqt] = q[pt2] ;
} else Lq[++Lqt] = q[pt2] ;
}
for( int i = 1 ; i <= Lot ; i ++ ) B.Modify( Lo[i].y , -Lo[i].delta ) ;
if( xL == xR ) return ;
while( pt1 <= oR )
if( o[pt1].x <= mid ) Lo[++Lot] = o[pt1++] ;
else Ro[++Rot] = o[pt1++] ;
memcpy( o + oL , Lo + 1 , Lot * sizeof( options ) ) ;
memcpy( o + oL + Lot , Ro + 1 , Rot * sizeof( options ) ) ;
memcpy( q + qL , Lq + 1 , Lqt * sizeof( queries ) ) ;
memcpy( q + qL + Lqt , Rq + 1 , Rqt * sizeof( queries ) ) ;
if( Lqt && Lot ) CDQ( oL , oL + Lot - 1 , qL , qL + Lqt - 1 , xL , mid ) ;
if( Rqt && Rot ) CDQ( oR - Rot + 1 , oR , qR - Rqt + 1 , qR , mid+1,xR ) ;
}
void solve(){
CDQ( 1 , ocnt , 1 , qcnt , 0 , N ) ;
for( int i = 1 ; i <= Qcnt ; i ++ )
printf( "%d\n" , ans[i] ) ;
}
int main(){
scanf( "%d" , &N ) ;
for( int i = 1 , u , v ; i < N ; i ++ ){
scanf( "%d%d" , &u , &v ) ;
In( u , v ) ; In( v , u ) ;
}
preWork() ;
solve() ;
}