Luogu-3250 [HNOI2016]网络

Luogu-3250 [HNOI2016]网络

题面

Luogu-3250

题解

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;
}
posted @ 2018-12-26 21:35  nianheng  阅读(121)  评论(0编辑  收藏  举报