【整体二分】洛谷P3242接水果

整体二分

就是把序列中答案在\([l,mid]\)的划到一个序列中,在\([mid+1,r]\)的划到另一个序列中,再对新生成的序列重复上述操作

容易发现最多只会划分log次


路径\((u,v)\)覆盖路径\((x,y)\)=\(u\)在\(x\)子树中,\(v\)在\(y\)子树中

\(x\)为\(y\)祖先要特殊讨论

这样就可以转成二维偏序

二分答案\(mid\),把权值\(>mid\)都塞进树状数组,套个整体二分就没了

#include <bits/stdc++.h>
#define N 40005
#define ll long long
#define For(i,x,y) for(int i=(x);i<=(y);++i)
#define Rof(i,x,y) for(int i=(x);i>=(y);--i)
using namespace std;

struct qwq{ int U,V,W; } pl[N];
struct ques{ int x,ly,ry,val,id; } q[N<<2];
struct owo{ int x,y,k,id; }fr[N];
vector<owo> v[N<<2];
vector<ques>pr[N<<2]; 
vector<int> g[N];
int c[N],d[N],lg[N],dfn[N],low[N],n,PL,FR,dep[N],cnt,tot,f[N][16],ans[N],tmp[N];

bool cmp2(const ques &x,const ques &y){ return x.x<y.x; }
bool cmp3(const owo &x,const owo &y){ return x.x<y.x; }

void dfs(int x){
    dfn[x]=++cnt;
    For(i,1,lg[dep[x]]) f[x][i]=f[f[x][i-1]][i-1];
    for(auto to:g[x]) if(!dfn[to]) dep[to]=dep[x]+1,f[to][0]=x,dfs(to);
    low[x]=cnt;
}
int getP(int x,int k){
    Rof(i,lg[k],0) if((k>>i)&1) x=f[x][i];
    return x;
}

void add(int l,int r,int val){
    for(int i=l;i<=n;i+=(i&(-i))) c[i]+=val;
    for(int i=r+1;i<=n;i+=(i&(-i))) c[i]-=val;
}
int qry(int x){
    int res=0;
    for(int i=x;i;i-=(i&(-i))) res+=c[i];
    return res;
}

void solve(int o,int lans,int rans){
    if(!v[o].size()) return;
    if(lans==rans){
        for(auto xx:v[o]) ans[xx.id]=d[lans];
        v[o].clear(),pr[o].clear();
        return;
    }
    int mid=(lans+rans)>>1,j=0;
    For(i,1,FR) tmp[i]=0;
    For(i,1,n) c[i]=0;
    For(i,0,(int)pr[o].size()-1){
        if(pl[pr[o][i].id].W<=mid){
            add(pr[o][i].ly,pr[o][i].ry,pr[o][i].val);
            pr[o<<1].push_back(pr[o][i]);
        } else pr[o<<1|1].push_back(pr[o][i]);
        while(j<(int)v[o].size() && v[o][j].x>=pr[o][i].x && (i==(int)pr[o].size()-1 || v[o][j].x<pr[o][i+1].x))
            tmp[v[o][j].id]=qry(v[o][j].y),j++;
    }

    for(auto xx:v[o]){
        if(tmp[xx.id]>=xx.k) v[o<<1].push_back(xx);
        else xx.k-=tmp[xx.id],v[o<<1|1].push_back(xx);
    }
    v[o].clear(),pr[o].clear();
    solve(o<<1,lans,mid);
    solve(o<<1|1,mid+1,rans);
}

int main(){
    int a,b,w;
    scanf("%d%d%d",&n,&PL,&FR);
    For(i,2,n) lg[i]=lg[i>>1]+1;
    For(i,1,n-1) scanf("%d%d",&a,&b),g[a].push_back(b),g[b].push_back(a);
    dep[0]=-1,dfs(1);
    
    For(i,1,PL) scanf("%d%d%d",&pl[i].U,&pl[i].V,&pl[i].W),d[i]=pl[i].W;
    sort(d+1,d+PL+1); int sz=unique(d+1,d+PL+1)-d-1;
    For(i,1,PL) pl[i].W=lower_bound(d+1,d+sz+1,pl[i].W)-d;
    
    For(i,1,PL){
        if(dfn[pl[i].U]>dfn[pl[i].V]) swap(pl[i].U,pl[i].V);
        if(dfn[pl[i].V]>=dfn[pl[i].U] && dfn[pl[i].V]<=low[pl[i].U]){
            int z=getP(pl[i].V,dep[pl[i].V]-dep[pl[i].U]-1);
            q[++tot]=(ques){1,dfn[pl[i].V],low[pl[i].V],1,i};
            q[++tot]=(ques){dfn[z],dfn[pl[i].V],low[pl[i].V],-1,i};
            if(low[z]+1<=n){
                q[++tot]=(ques){dfn[pl[i].V],low[z]+1,n,1,i};
                q[++tot]=(ques){low[pl[i].V]+1,low[z]+1,n,-1,i};
            }
        } else{
            q[++tot]=(ques){dfn[pl[i].U],dfn[pl[i].V],low[pl[i].V],1,i};
            q[++tot]=(ques){low[pl[i].U]+1,dfn[pl[i].V],low[pl[i].V],-1,i};
        }
    }
    q[tot+1].x=n+1;
    sort(q+1,q+tot+1,cmp2);
    For(i,1,tot) pr[1].push_back(q[i]);
    
    For(i,1,FR){
        scanf("%d%d%d",&a,&b,&w);
        if(dfn[a]>dfn[b]) swap(a,b);
        fr[i]=(owo){dfn[a],dfn[b],w,i};
    }
    sort(fr+1,fr+FR+1,cmp3);
    
    For(i,1,n) v[1].push_back(fr[i]);
    solve(1,1,sz);
    For(i,1,FR) printf("%d\n",ans[i]);
}
上一篇:习题:A(数位DP&状压)


下一篇:爬取湖北师范大学招生信息网中的专业简介