[HNOI2015][bzoj4009] 接水果 [整体二分+扫描线]

题面

传送门

思路

本题其实有在线做法......但是太难写了,退而求其次写了离线

基本思路就是,考虑一个盘子以及它能接到的所有水果

可以发现,这个水果的端点一定在这个盘子两端的“子树”内(加引号是因为可能是一条链顶端外面的“子树”)

那么,可以把模型抽象成:盘子就是矩形,两个端点就是两个维度上的限制,而水果就是点

一个水果可以被接住,当且仅当这个水果的点在某个盘子的矩形内部

考虑盘子的不同情况:

如果盘子是有一个折点的折链,那么两边的限制,就是两个端点的子树dfs序范围

如果盘子是一条从下到上的链,那么这个矩形实际上是有两个的:

假设链是(u,v),u是v的祖先,这条链上从u开始下一个点是x

那么,其中一维的限制显然是$[dfn[v],last[v]]$,

但是另一维上的限制实际上有两个拼起来:

$[1,dfn[x]-1]$和$[last[x]+1,n]$

这里实际上是得到了$u$外面的“子树”的dfs序范围

我们把这些链拆成矩形,然后跑一个整体二分,每次二分每个水果被多少个矩形覆盖

当前二分区间是$[l,r]$,如果$[l,mid]$中的覆盖矩形的数量大于要求的数量,就进入左边

否则,要求的数量减去这个覆盖矩形数量,并进入右边

这样总复杂度是$O(n\log^2n)$

实现的时候,可以把矩形的两个维度中小的那个放在x,大的放在y,注意这里不要写错了

Code

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cassert>
#include<queue>
#include<cmath>
#define las DEEP_DARK_FANTASY
#define lowbit(x) (x&(-x))
#define mp make_pair
using namespace std;
namespace IO
{
    const int __S=(1<<20)+5;char __buf[__S],*__H,*__T;
    inline char getc()
    {
        if(__H==__T) __T=(__H=__buf)+fread(__buf,1,__S,stdin);
        if(__H==__T) return -1;
        return *__H++;
    }
    template <class __I>inline void read(__I &__x)
    {
        __x=0;int __fg=1;char __c=getc();
        while(!isdigit(__c)&&__c!='-') __c=getc();
        if(__c=='-') __fg=-1,__c=getc();
        while(isdigit(__c)) __x=__x*10+__c-'0',__c=getc();
        __x*=__fg;
    }
    inline void readd(double &__x)
    {
        __x=0;double __fg=1.0;char __c=getc();
        while(!isdigit(__c)&&__c!='-') __c=getc();
        if(__c=='-') __fg=-1.0,__c=getc();
        while(isdigit(__c)) __x=__x*10.0+__c-'0',__c=getc();
        if(__c!='.'){__x=__x*__fg;return;}else while(!isdigit(__c)) __c=getc();
        double __t=1e-1;while(isdigit(__c)) __x=__x+1.0*(__c-'0')*__t,__t=__t*0.1,__c=getc();
        __x=__x*__fg;
    }
    inline void reads(char *__s,int __x)
    {
        char __c=getc();int __tot=__x-1;
        while(__c<'a'||__c>'z') __c=getc();
        while(__c>='a'&&__c<='z') __s[++__tot]=__c,__c=getc();
        __s[++__tot]='\0';
    }
    char __obuf[__S],*__oS=__obuf,*__oT=__oS+__S-1,__c,__qu[55];int __qr;
    inline void flush(){fwrite(__obuf,1,__oS-__obuf,stdout);__oS=__obuf;}
    inline void putc(char __x){*__oS++ =__x;if(__oS==__oT) flush();}
    template <class __I>inline void print(__I __x)
    {
        if(!__x) putc('0');
        if(__x<0) putc('-'),__x=-__x;
        while(__x) __qu[++__qr]=__x%10+'0',__x/=10;
        while(__qr) putc(__qu[__qr--]);
    }
    inline void prints(const char *__s,const int __x)
    {
        int __len=strlen(__s+__x);
        for(int __i=__x;__i<__len+__x;__i++) putc(__s[__i]);
    }
    inline void printd(long double __x,int __d)
    {
        long long __t=(long long)floor(__x);print(__t);putc('.');__x-=(double)__t;
        while(__d--)
        {
            long double __y=__x*10.0;__x*=10.0;
            int __c=(int)floor(__y+1e-9);if(__c==10) __c--;
            putc(__c+'0');__x-=floor(__y);
        }
    }
    inline void el(){putc('\n');}inline void sp(){putc(' ');}
}using namespace IO;

inline int read(){
    int re=0,flag=1;char ch=getchar();
    while(!isdigit(ch)){
        if(ch=='-') flag=-1;
        ch=getchar();
    }
    while(isdigit(ch)) re=(re<<1)+(re<<3)+ch-'0',ch=getchar();
    return re*flag;
}
int n,m,k,first[40010],cnte,dfn[40010],las[40010],st[40010][20],dep[40010],clk;
struct edge{
    int to,next;
}a[100010];
inline void add(int u,int v){
    a[++cnte]=(edge){v,first[u]};first[u]=cnte;
    a[++cnte]=(edge){u,first[v]};first[v]=cnte;
}
void dfs(int u,int f){
    int i,v;
    st[u][0]=f;dep[u]=dep[f]+1;
    dfn[u]=++clk;
    for(i=first[u];~i;i=a[i].next){
        v=a[i].to;if(v==f) continue;
        dfs(v,u);
    }
    las[u]=clk;
}
void ST(){
    int i,j;
    for(j=1;j<=16;j++)
        for(i=1;i<=n;i++)
            st[i][j]=st[st[i][j-1]][j-1];
}
int getpre(int l,int r){
    int i;
    if(l==r) return l;
    if(dep[l]>dep[r]) swap(l,r);
    for(i=16;i>=0;i--) if(dep[st[r][i]]>dep[l]) r=st[r][i];
    if(st[r][0]==l) return r;
    else return 0;
}
struct mat{
    int lx,rx,ly,ry,val,id;
}p[100010];int cntp;
inline bool cmp(mat l,mat r){
    return l.val<r.val;
}
struct fru{
    int x,y,id,ans,k;
}f[40010];
struct ele{
    int l,r,id;
};
namespace BIT{
    int a[100010];
    void Add(int x,int val){
        for(;x<=n;x+=lowbit(x)) a[x]+=val;
    }
    void add(int l,int r,int val){
        Add(l,val);Add(r+1,-val);
    }
    int sum(int x){
        int re=0;
        for(;x>0;x-=lowbit(x)) re+=a[x];
        return re;
    }
}
queue<ele>q;
vector<int>s,le,ri;
vector<pair<int,int> >t;
inline bool cmps(int l,int r){
    return f[l].x<f[r].x;
}
inline bool cmpt(pair<int,int>l,pair<int,int>r){
    int vl,vr;
    if(l.second) vl=p[l.first].rx;
    else vl=p[l.first].lx;
    if(r.second) vr=p[r.first].rx;
    else vr=p[r.first].lx;
    return vl<vr;
}
void solve(){
    ele cur;int i,l,r,mid,j,tmp,tval;
    for(i=1;i<=k;i++) q.push((ele){1,cntp,i});

    while(!q.empty()){
        cur=q.front();q.pop();
        if(cur.l==cur.r){f[cur.id].ans=p[cur.l].val;continue;}
        l=cur.l;
        r=cur.r;
        s.clear();
        s.push_back(cur.id);
        mid=(l+r)>>1;t.clear();

        while(!q.empty()&&q.front().l==l&&q.front().r==r){
            s.push_back(q.front().id);
            q.pop();
        }
        sort(s.begin(),s.end(),cmps);

        for(i=l;i<=mid;i++){
            t.push_back(mp(i,0));
            t.push_back(mp(i,1));
        }
        sort(t.begin(),t.end(),cmpt);

        j=-1;le.clear();ri.clear();
        for(i=0;i<t.size();i++){
            if(t[i].second) tmp=p[t[i].first].rx;
            else tmp=p[t[i].first].lx;

            while((j<((int)s.size()-1))&&(f[s[j+1]].x<tmp)){
                j++;tval=BIT::sum(f[s[j]].y);
                if(tval<f[s[j]].k){
                    f[s[j]].k-=tval;
                    ri.push_back(s[j]);
                }
                else{
                    le.push_back(s[j]);
                }
            }
            if(t[i].second) BIT::add(p[t[i].first].ly,p[t[i].first].ry,-1);
            else BIT::add(p[t[i].first].ly,p[t[i].first].ry,1);
        }
        while(j<((int)s.size()-1)){
            j++;tval=BIT::sum(f[s[j]].y);
            if(tval<f[s[j]].k){
                f[s[j]].k-=tval;
                ri.push_back(s[j]);
            }
            else{
                le.push_back(s[j]);
            }
        }
        for(auto lef:le) q.push((ele){l,mid,lef});
        for(auto rig:ri) q.push((ele){mid+1,r,rig});
    }
}
int main(){
    read(n);read(m);read(k);
    int i,t1,t2,t3,tmp;
    memset(first,-1,sizeof(first));
    for(i=1;i<n;i++){
        read(t1);read(t2);
        add(t1,t2);
    }
    dfs(1,0);ST();
    for(i=1;i<=m;i++){
        read(t1);read(t2);read(t3);
        if(dep[t2]<dep[t1]) swap(t1,t2);
        tmp=getpre(t1,t2);
        if(tmp){
            if(dfn[tmp]>1) p[++cntp]=(mat){1,dfn[tmp]-1+1,dfn[t2],las[t2],t3,i};
            if(las[tmp]<n) p[++cntp]=(mat){dfn[t2],las[t2]+1,las[tmp]+1,n,t3,i};
        }
        else{
            if(dfn[t2]<dfn[t1]) swap(t1,t2);
            p[++cntp]=(mat){dfn[t1],las[t1]+1,dfn[t2],las[t2],t3,i};
        }
    }
    
    sort(p+1,p+cntp+1,cmp);

    for(i=1;i<=k;i++){
        read(t1);read(t2);read(t3);
        if(dfn[t1]>dfn[t2]) swap(t1,t2);
        f[i]=(fru){dfn[t1],dfn[t2],i,0,t3};
    }
    solve();
    for(i=1;i<=k;i++) print(f[i].ans),el();
    flush();
}

转载于:https://www.cnblogs.com/dedicatus545/p/9800900.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值