[HNOI2016]网络

 [HNOI2016]网络 

未影响的最大值??

最值不能差分之类,难处理

二分答案!看是否覆盖所有大于mid路径!可以计数!树状数组维护dfn序,树上差分

多组询问?整体二分!

#include<bits/stdc++.h>
#define reg register int
#define il inline
#define fi first
#define se second
#define mk(a,b) make_pair(a,b)
#define numb (ch^'0')
using namespace std;
typedef long long ll;
template<class T>il void rd(T &x){
    char ch;x=0;bool fl=false;
    while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true);
    for(x=numb;isdigit(ch=getchar());x=x*10+numb);
    (fl==true)&&(x=-x);
}
template<class T>il void output(T x){if(x/10)output(x/10);putchar(x%10+'0');}
template<class T>il void ot(T x){if(x<0) putchar('-'),x=-x;output(x);putchar(' ');}
template<class T>il void prt(T a[],int st,int nd){for(reg i=st;i<=nd;++i) ot(a[i]);putchar('\n');}

namespace Miracle{
const int N=1e5+5;
const int M=2e5+5;
const int inf=1e9;
int n,m;
struct node{
    int nxt,to;
}e[2*N];
int hd[N],cnt;
void add(int x,int y){
    e[++cnt].nxt=hd[x];
    e[cnt].to=y;
    hd[x]=cnt;
}
int dep[N],fa[N][18];
int dfn[N],dfn2[N],fdfn[N];
int df;
void dfs(int x,int d){
    dep[x]=d;
    dfn[x]=++df;fdfn[df]=x;
    for(reg i=hd[x];i;i=e[i].nxt){
        int y=e[i].to;
        if(y==fa[x][0]) continue;
        fa[y][0]=x;
        dfs(y,d+1);
    }
    dfn2[x]=df;
}
int lca(int x,int y){
    if(dep[x]<dep[y]) swap(x,y);
    for(reg j=17;j>=0;--j){
        if(dep[fa[x][j]]>=dep[y]) x=fa[x][j];
    }
    if(x==y) return x;
    for(reg j=17;j>=0;--j){
        if(fa[x][j]!=fa[y][j]) x=fa[x][j],y=fa[y][j];
    }
    return fa[x][0];
}
struct po{
    int x,y,anc,val;
}p[M];
struct event{//typ=1:add -1:dele 2:query
    int typ;
    int id,pos;
}q[M],le[M],ri[M];
int tot;
int ans[N];
int f[N];
void upda(int x,int c){
    if(!x) return;
    for(;x<=n;x+=x&(-x)) f[x]+=c;
}
int query(int x){
    int ret=0;
    for(;x;x-=x&(-x)) ret+=f[x];return ret;
}
void divi(int l,int r,int L,int R){
//    cout<<" divi "<<l<<" and "<<r<<" : "<<L<<" && "<<R<<endl;
    if(l>r) return;
    if(L==R){
        for(reg i=l;i<=r;++i){
            if(q[i].typ==2){
                if(L==0) ans[q[i].id]=-1;
                else ans[q[i].id]=L;
            }
        }
        return ;
    }
    int mid=(L+R)>>1;
    int pl=0,pr=0;
    int cnt=0;
    for(reg i=l;i<=r;++i){
//        cout<<" i "<<i<<" typ "<<q[i].typ<<endl;
        if(q[i].typ==2){//query
            int now=query(dfn2[q[i].pos])-query(dfn[q[i].pos]-1);
            if(now<cnt){
                ri[++pr]=q[i];
            }else le[++pl]=q[i];
        }else{
            if(p[q[i].id].val>mid){
                int lp=q[i].typ;
                cnt+=lp;
                upda(dfn[p[q[i].id].x],lp);
                upda(dfn[p[q[i].id].y],lp);
                upda(dfn[p[q[i].id].anc],-lp);
                upda(dfn[fa[p[q[i].id].anc][0]],-lp);
                ri[++pr]=q[i];
            }else{
                le[++pl]=q[i];
            }
        }
    }
    for(reg i=l;i<=r;++i){
        if(q[i].typ==2){//query
            continue;
        }else{
            if(p[q[i].id].val>mid){
                int lp=q[i].typ;
                upda(dfn[p[q[i].id].x],-lp);
                upda(dfn[p[q[i].id].y],-lp);
                upda(dfn[p[q[i].id].anc],lp);
                upda(dfn[fa[p[q[i].id].anc][0]],lp);
            }
        }
    }
    for(reg i=1;i<=pl;++i){
        q[i+l-1]=le[i];
    }
    for(reg i=1;i<=pr;++i){
        q[l+pl-1+i]=ri[i];
    }
    divi(l,l+pl-1,L,mid);
    divi(l+pl,r,mid+1,R);
}
int main(){
    rd(n);rd(m);
    int x,y;
    for(reg i=1;i<n;++i) {
        rd(x);rd(y);add(x,y);add(y,x);
    }
    dfs(1,1);
    for(reg j=1;j<=17;++j){
        for(reg i=1;i<=n;++i){
            fa[i][j]=fa[fa[i][j-1]][j-1];
        }
    }
    for(reg i=1;i<=m;++i){
        rd(q[i].typ);
        if(q[i].typ==0){
            q[i].typ=1;
            rd(p[i].x);rd(p[i].y);rd(p[i].val);
            p[i].anc=lca(p[i].x,p[i].y);
            q[i].id=i;
        }    
        else if(q[i].typ==1){
            q[i].typ=-1;
            rd(x);q[i].id=x;
        }else{
            ++tot;q[i].id=tot;
            rd(q[i].pos);
        }
    }
    divi(1,m,0,inf);
    for(reg i=1;i<=tot;++i){
        printf("%d\n",ans[i]);
    }
    return 0;
}

}
signed main(){
    Miracle::main();
    return 0;
}

/*
   Author: *Miracle*
   Date: 2019/3/22 17:15:06
*/

最优化有时难以直接考虑,二分是一个不错的转化为判定问题,有时还可以转化为计数

posted @ 2019-03-22 18:59  *Miracle*  阅读(165)  评论(0编辑  收藏  举报