• BZOJ4009: [HNOI2015]接水果


    4009: [HNOI2015]接水果

    Description

    风见幽香非常喜欢玩一个叫做 osu!的游戏,其中她最喜欢玩的模式就是接水果。

    由于她已经DT FC The big black,  她觉得这个游戏太简单了,于是发明了一个更

    加难的版本。首先有一个地图,是一棵由 个顶点、n-1 条边组成的树(例如图 1

    给出的树包含 个顶点、条边)。这颗树上有 个盘子,每个盘子实际上是一条

    路径(例如图 中顶点 到顶点 的路径),并且每个盘子还有一个权值。第 

    盘子就是顶点a_i到顶点b_i的路径(由于是树,所以从a_ib_i的路径是唯一的)

    权值为c_i。接下来依次会有Q个水果掉下来,每个水果本质上也是一条路径,第

    个水果是从顶点 u_i 到顶点v_i 的路径。幽香每次需要选择一个盘子去接当前的水

    果:一个盘子能接住一个水果,当且仅当盘子的路径是水果的路径的子路径(例如

    1中从 3的路径是从18的路径的子路径)。这里规定:b的路径与

    b到 a的路径是同一条路径。当然为了提高难度,对于第 个水果,你需要选择

    能接住它的所有盘子中,权值第 k_i 小的那个盘子,每个盘子可重复使用(没有使用次数

    的上限:一个盘子接完一个水果后,后面还可继续接其他水果,只要它是水

    果路径的子路径)。幽香认为这个游戏很难,你能轻松解决给她看吗? 

    Input

    第一行三个数 nQ,表示树的大小和盘子的个数和水果的个数。 

    接下来n-1 行,每行两个数 ab,表示树上的a之间有一条边。树中顶点

    1到 n标号。 接下来 行,每行三个数 abc,表示路径为 到 b、权值为 的盘子,其

    0≤c≤10^9a不等于b 

    接下来Q行,每行三个数 uvk,表示路径为 u到 v的水果,其中 u不等于v,你需要选择第 k小的盘子,

    小一定存在。 

    Output

     对于每个果子,输出一行表示选择的盘子的权值。 

    Sample Input

    10 10 10 
    1 2 
    2 3 
    3 4 
    4 5 
    5 6 
    6 7 
    7 8 
    8 9 
    9 10 
    3 2 217394434 
    10 7 13022269 
    6 7 283254485 
    6 8 333042360 
    4 6 442139372 
    8 3 225045590 
    10 4 922205209 
    10 8 808296330 
    9 2 486331361 
    4 9 551176338 
    1 8 5 
    3 8 3 
    3 8 4 
    1 8 3 
    4 8 1 
    2 3 1 
    2 3 1 
    2 3 1 
    2 4 1 
    1 4 1 

    Sample Output

    442139372 
    333042360 
    442139372 
    283254485 
    283254485 
    217394434 
    217394434 
    217394434 
    217394434 
    217394434 

    HINT

    N,P,Q<=40000 

    整体二分还挺好写的囧

    考虑一条路径A被另一条路径B包含的条件是:
    设A的两端点为x,y,B的两端点为u,v。

    当x、y构成了祖先关系时,设y为祖先、z为x到y路径上倒数第二个点,则u和v有一个应在x的子树中,另一个不在z的子树中。

    当x、y不构成祖先关系时,则u和v有一个应在x的子树中,另一个在y的子树中。

    那么一个盘子就可以变成一个或两个矩形,一个果子就可以对应一个二维点。

    然后可以整体二分,问题转化成计算有多少个矩形包含了一个二维点。

    #include<cstdio>
    #include<cctype>
    #include<queue>
    #include<cmath>
    #include<cstring>
    #include<algorithm>
    #define rep(i,s,t) for(int i=s;i<=t;i++)
    #define dwn(i,s,t) for(int i=s;i>=t;i--)
    #define ren for(int i=first[x];i;i=next[i])
    using namespace std;
    const int BufferSize=1<<16;
    char buffer[BufferSize],*head,*tail;
    inline char Getchar() {
        if(head==tail) {
            int l=fread(buffer,1,BufferSize,stdin);
            tail=(head=buffer)+l;
        }
        return *head++;
    }
    inline int read() {
        int x=0,f=1;char c=Getchar();
        for(;!isdigit(c);c=Getchar()) if(c=='-') f=-1;
        for(;isdigit(c);c=Getchar()) x=x*10+c-'0';
        return x*f;
    }
    const int maxn=40010;
    int n,m,q,first[maxn],next[maxn<<1],to[maxn<<1],e;
    void AddEdge(int u,int v) {
        to[++e]=v;next[e]=first[u];first[u]=e;
        to[++e]=u;next[e]=first[v];first[v]=e;
    }
    int st[maxn],en[maxn],dep[maxn],anc[maxn][20],ToT;
    void dfs(int x,int fa) {
        anc[x][0]=fa;rep(i,1,19) anc[x][i]=anc[anc[x][i-1]][i-1];
        st[x]=++ToT;dep[x]=dep[fa]+1;
        ren if(to[i]!=fa) dfs(to[i],x);
        en[x]=ToT;
    }
    int swim(int x,int k) {
        rep(i,0,19) if(k>>i&1) x=anc[x][i];
        return x;
    }
    struct Plate {
        int x,y,l,r,val;
        bool operator < (const Plate& ths) const {return val<ths.val;}
    }A[maxn<<1];
    struct Apple {int x,y,k,id;}B[maxn];
    struct Sol1 {
        int x,l,r,val;
        bool operator < (const Sol1& ths) const {return x<ths.x;}
    }T[maxn<<2];
    struct Sol2 {
        int x,y,id;
        bool operator < (const Sol2& ths) const {return x<ths.x;}
    }C[maxn<<1];
    int Q[maxn],ans[maxn],now[maxn],cur[maxn],sumv[maxn],Tmp[maxn],clo;
    int query(int x) {
        int res=0;
        for(;x;x-=x&-x) if(cur[x]==clo) res+=sumv[x];
        return res;
    }
    void add(int x,int v) {
        for(;x<=n;x+=x&-x) {
            if(cur[x]!=clo) cur[x]=clo,sumv[x]=v;
            else sumv[x]+=v;
        }
    }
    void solve(int l,int r,int h,int t) {
        if(h>t) return;
        if(l==r) {
            rep(i,h,t) ans[B[Q[i]].id]=A[l].val;
            return;
        }
        int mid=l+r>>1,m1=0,m2=0;
        rep(i,l,mid) if(A[i].l<=A[i].r) {
            T[++m1]=(Sol1){A[i].x,A[i].l,A[i].r,1};
            T[++m1]=(Sol1){A[i].y+1,A[i].l,A[i].r,-1};
        }
        rep(i,h,t) {
            C[++m2]=(Sol2){B[Q[i]].x,B[Q[i]].y,i};
            C[++m2]=(Sol2){B[Q[i]].y,B[Q[i]].x,i};
            now[i]=0;
        }
        clo++;sort(T+1,T+m1+1);sort(C+1,C+m2+1);
        int j=1;
        rep(i,1,m2) {
            while(j<=m1&&T[j].x<=C[i].x) add(T[j].l,T[j].val),add(T[j].r+1,-T[j].val),j++;
            now[C[i].id]+=query(C[i].y);
        }
        int L=h,R=t;
        rep(i,h,t) {
            if(now[i]>=B[Q[i]].k) Tmp[L++]=Q[i];
            else B[Q[i]].k-=now[i],Tmp[R--]=Q[i];
        }
        rep(i,h,t) Q[i]=Tmp[i];
        solve(l,mid,h,R);solve(mid+1,r,R+1,t);
    }
    int main() {
        n=read();m=read();q=read();
        rep(i,2,n) AddEdge(read(),read());
        dfs(1,0);int tmp=0;
        rep(i,1,m) {
            int x=read(),y=read(),v=read();
            if(dep[x]<dep[y]) swap(x,y);
            if(st[x]>=st[y]&&st[x]<=en[y]) {
                y=swim(x,dep[x]-dep[y]-1);
                A[++tmp]=(Plate){st[x],en[x],1,st[y]-1,v};
                A[++tmp]=(Plate){st[x],en[x],en[y]+1,n,v};
            }
            else A[++tmp]=(Plate){st[x],en[x],st[y],en[y],v};
        }
        m=tmp;sort(A+1,A+m+1);
        rep(i,1,q) {
            Q[i]=i;int x=read(),y=read(),val=read();
            B[i]=(Apple){st[x],st[y],val,i};
        }
        solve(1,m,1,q);
        rep(i,1,q) printf("%d
    ",ans[i]);
        return 0;
    }
    View Code
  • 相关阅读:
    菜根谭#77
    菜根谭#76
    菜根谭#75
    菜根谭#74
    菜根谭#73
    python迭代器
    python爬取网页数据
    yii2验证规则
    python装饰器的理解
    php中多图上传采用数组差集处理(array_diff,array_map)
  • 原文地址:https://www.cnblogs.com/wzj-is-a-juruo/p/5231727.html
Copyright © 2020-2023  润新知