Luogu-3250 [HNOI2016]网络
Luogu-3250 [HNOI2016]网络
题面
题解
CDQ分治...这个应该算是整体二分吧
二分重要度,按照时间从小到大加入大于重要度的边
对于一个询问,如果经过这个点的边数不等于加入的边数,那就说明有比重要度大而且不经过这个点的边,然后分成两部分继续做
看Candy?大佬的博客学会了一种加边方法:记录dfn序,对于一条边\(u\),\(v\)。让端点的\(cnt\)++,\(lca\)和\(fa[lca]\)的--,找经过一个点边数只需要查询他的子树大小就好啦
代码
#include<map>
#include<queue>
#include<cmath>
#include<ctime>
#include<stack>
#include<bitset>
#include<vector>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
inline char gc(){
//static char buf[100000],*p1,*p2;
//return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
return getchar();
}
inline int read(){
int ans=0,fh=1;
char ch=gc();
while(ch<'0'||ch>'9'){if(ch=='-') fh=-1; ch=gc();}
while(ch>='0'&&ch<='9') ans=(ans<<1)+(ans<<3)+ch-'0',ch=gc();
return ans*fh;
}
const int maxn=2e5+100,maxm=maxn<<1;
struct node{
int a,b,v;
}c[maxn];
int n,m,head[maxn],nex[maxm],v[maxm],num=1;
int tre[maxn],cr[maxn],cl;
int fa[maxn],top[maxn],siz[maxn],dep[maxn],son[maxn],dfn[maxn],tim;
int tmp1[maxn],tmp2[maxn],p[maxn],ans[maxn],mx,qtot;
void revise(int x,int z){
for(int i=x;i<maxn;i+=i&(-i))
if(cr[i]==cl) tre[i]+=z;
else cr[i]=cl,tre[i]=z;
}
int query(int x,int Ans=0){
for(int i=x;i;i-=i&(-i))
if(cr[i]==cl) Ans+=tre[i];
return Ans;
}
void add(int x,int y){
v[++num]=y;
nex[num]=head[x];
head[x]=num;
v[++num]=x;
nex[num]=head[y];
head[y]=num;
}
void dfs1(int x,int f,int dp){
fa[x]=f,dep[x]=dp,siz[x]=1;
for(int i=head[x];i;i=nex[i]){
int y=v[i];
if(y==f) continue;
dfs1(y,x,dp+1);
if(siz[y]>siz[son[x]])
son[x]=y;
siz[x]+=siz[y];
}
}
void dfs2(int x,int tp){
top[x]=tp,dfn[x]=++tim;
if(son[x]) dfs2(son[x],tp);
for(int i=head[x];i;i=nex[i])
if(v[i]!=fa[x]&&v[i]!=son[x])
dfs2(v[i],v[i]);
}
int Lca(int x,int y){
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]]) swap(x,y);
x=fa[top[x]];
}
return dep[x]<dep[y]?x:y;
}
void work(int x,int y,int z){
int lca=Lca(x,y);
revise(dfn[x],z),revise(dfn[y],z);
revise(dfn[lca],-z);if(lca!=1) revise(dfn[fa[lca]],-z);
}
int check(int x){
int l=dfn[x],r=dfn[x]+siz[x]-1;
return query(r)-query(l-1);
}
void cdq(int l,int r,int L,int R){
if(L>R) return;
if(l==r){
int ltot=0;cl++;
for(int i=L;i<=R;i++){
int x=p[i],z=c[x].v>0?1:-1;
if(~c[x].b) work(c[x].a,c[x].b,z),ltot+=z;
else if(check(c[x].a)!=ltot) ans[c[x].v]=l;
}
return;
}
int mid=l+r>>1;
int lc=0,rc=0,cnt=L-1,ltot=0;cl++;
for(int i=L;i<=R;i++){
int x=p[i],z=c[x].v>0?1:-1;
if(~c[x].b){
if(abs(c[x].v)>mid)
work(c[x].a,c[x].b,z),tmp2[++rc]=x,ltot+=z;
else tmp1[++lc]=x;
}
else{
int pp=check(c[x].a);
if(pp!=ltot) tmp2[++rc]=x;
else tmp1[++lc]=x;
}
}
for(int i=1;i<=lc;i++) p[++cnt]=tmp1[i];
for(int i=1;i<=rc;i++) p[++cnt]=tmp2[i];
cdq(l,mid,L,L+lc-1),cdq(mid+1,r,L+lc,R);
}
int main(){
// freopen("3250.in","r",stdin);
n=read(),m=read();
int x,y,ms,z;
for(int i=1;i<n;i++)
x=read(),y=read(),add(x,y);
dfs1(1,1,1);
dfs2(1,1);
for(int i=1;i<=m;i++){
ms=read(),p[i]=i;
if(!ms){
x=read(),y=read(),z=read();
c[i]=(node){x,y,z},mx=max(mx,z);
}
else{
x=read();
if(ms==1) c[i]=c[x],c[i].v*=-1;
else c[i].a=x,c[i].b=-1,c[i].v=++qtot;
}
}
memset(ans,-1,sizeof(ans));
cdq(1,mx,1,m);
for(int i=1;i<=qtot;i++)
printf("%d\n",ans[i]);
return 0;
}