题解: 对于每个询问二分答案M,那么转为判断权值大于等于M的路径的交是否包含该点。
建立权值线段树,区间
[
L
,
R
]
[L,R]
[L,R]维护权值在
[
L
,
R
]
[L,R]
[L,R]范围内的线段的交,可以O(1)合并左右子树的答案。
那么二分答案的过程可以改为线段树上二分的过程,
O
(
log
n
)
O(\log n)
O(logn)
插入和删除在没有权值相等的情况下就是简单的把某一个位置赋值或者清零然后向上合并即可。
权值相等时或许可以按照其为第y个出现的权值为x的数,以y为第二关键字排序,最后把排完序后的数组作为离散化后的数组为新的权值来二分,输出的时候对于旧的
l
o
w
e
r
_
b
o
u
n
d
lower\_bound
lower_bound一下即可。
没有代码。
upd:
我终于拿到了一个LOJ的RK1了!!!!!!2019-10-03 19:19:13
AC
Code:
\texttt{AC Code:}
AC Code:
#include<bits/stdc++.h>
#define maxn 200005
#define lim 19
#define lc u<<1
#define rc u<<1|1
#define mp make_pair
using namespace std;
char cb[1000000],*cs=cb,*ct=cb;
#define getc() (cs==ct&&(ct=(cs=cb)+fread(cb,1,1000000,stdin),cs==ct)?0:*cs++)
void read(int &res){
char ch;
for(;!isdigit(ch=getc()););
for(res=ch-'0';isdigit(ch=getc());res=res*10+ch-'0');
}
char wb[1000000],*wa=wb;
int n,m;
int info[maxn],Prev[maxn],to[maxn],cnt,cnt_e;
pair<int,int>sb[maxn];
void Node(int u,int v){ Prev[++cnt_e]=info[u],info[u]=cnt_e,to[cnt_e]=v; }
int dat[maxn][4],st[lim][maxn],lg[maxn],pos[maxn],tot,dep[maxn];
void dfs(int u,int ff){
dep[u] = dep[ff] + 1;
st[0][pos[u] = ++tot] = u;
for(int i=info[u];i;i=Prev[i])
if(to[i]!=ff){
dfs(to[i],u);
st[0][++tot] = u;
}
}
inline int Lca(int u,int v){
u = pos[u] , v = pos[v];
if(u > v) swap(u,v);
int t = lg[v-u+1];
return dep[st[t][u]] < dep[st[t][v-(1<<t)+1]] ? st[t][u] : st[t][v-(1<<t)+1];
}
int pt[maxn<<2][2],M;
inline bool cmp(const int &u,const int &v){ return dep[u] > dep[v]; }
inline void merge(int *c,int *a,int *b){
if(a[0] == -1 || b[0] == -1) c[0] = c[1] = -1;
else if(!a[0] || !b[0]) c[0] = a[0] + b[0] , c[1] = a[1] + b[1];
else{
static int p[4] = {};
p[0] = Lca(a[0],b[0]) , p[1] = Lca(a[1],b[1]) , p[2] = Lca(a[1],b[0]) , p[3] = Lca(a[0],b[1]);
sort(p,p+4,cmp);
if(p[0] != p[1]) c[0] = p[0] , c[1] = p[1];
else if(p[0] == Lca(a[0],a[1]) || p[0] == Lca(b[0],b[1])) c[0] = c[1] = p[0] = p[1];
else c[0] = c[1] = -1;
}
}
inline bool chk(int u,int *p){
if(p[0] == -1) return 0;
if(p[0] == 0) return 1;
if(dep[u] < dep[Lca(p[0],p[1])]) return 0;
return Lca(u,p[0]) == u || Lca(u,p[1]) == u;
}
inline void Insert(int pos,int p1,int p2){
pos += M - 1;
for(pt[pos][0] = p1 , pt[pos][1] = p2;pos>1;pos>>=1)
merge(pt[pos>>1],pt[pos],pt[pos^1]);
}
inline int solve(int u,int l,int r,int t){
for(int mid;l<r;){
mid = (l+r) >> 1;
if(chk(t,pt[rc])) u=lc,r = mid;
else u=rc,l = mid+1;
}
return l;
}
void put(int a){
static int q[20]={};
if(a<0) *wa++ = '-' , a = -a;
for(;a;a/=10)q[++q[0]]=a%10;
if(!q[0]) *wa++ = '0';
for(;q[0];) *wa++ = (q[q[0]--] + '0');
}
int main(){
read(n),read(m);
for(int i=1,u,v;i<n;i++){
read(u),read(v);
Node(u,v),Node(v,u);
}
dfs(1,0);
for(int j=1;j<lim;j++)
for(int i=1;i<=tot-(1<<j)+1;i++)
st[j][i] = (dep[st[j-1][i]] < dep[st[j-1][i+(1<<j-1)]] ? st[j-1][i] : st[j-1][i+(1<<j-1)]);
for(int i=2;i<=tot;i++) lg[i] = lg[i>>1] + 1;
for(int i=1;i<=m;i++){
read(dat[i][0]),read(dat[i][1]);
if(dat[i][0] == 0) read(dat[i][2]),read(dat[i][3]),sb[++cnt] = mp(dat[i][3],i);
if(dat[i][0] == 1) dat[i][3] = dat[dat[i][1]][3];
}
sort(sb+1,sb+1+cnt);
for(M=1;M<cnt;M<<=1);
for(int i=1;i<=m;i++){
if(dat[i][0] <= 1)
dat[i][3] = lower_bound(sb+1,sb+1+cnt,mp(dat[i][3],dat[i][0] == 0 ? i : dat[i][1])) - sb;
if(dat[i][0] == 0) Insert(dat[i][3],dat[i][1],dat[i][2]);
if(dat[i][0] == 1) Insert(dat[i][3],0,0);
if(dat[i][0] == 2){
if(chk(dat[i][1],pt[1])) put(-1);
else put(sb[solve(1,1,M,dat[i][1])].first);
*wa++ = '\n';
}
}
fwrite(wb,1,wa-wb,stdout);
}