BZOJ 4009 HNOI2015 接水果 树套树

题目大意:给定一棵树和m条路径,每条路径有一个权值,Q次询问,每次询问某条路经包含的所有路径中权值的第k小

原来精神污染那个题是这么做的啊QwQ

题解网上都有,我就直接贴代码了

没心情写题解了

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 40400
using namespace std;
struct Line{
    int type;
    int x,y1,y2,z;
    Line() {}
    Line(int _,int __,int ___,int ____,int _____):
        type(_),x(__),y1(___),y2(____),z(_____) {}
    bool operator < (const Line &l) const
    {
        if(x!=l.x)
            return x < l.x;
        return type > l.type;
    }
}lines[M<<2];
struct Query{
    int x,y,k,id;
    bool operator < (const Query &q) const
    {
        return x < q.x ;
    }
}queries[M];
struct abcd{
    int to,next;
}table[M<<1];
int head[M],_tot;
int n,m,q,tot;
int dpt[M],fa[M][16],st[M],ed[M];
int ans[M];
void Add(int x,int y)
{
    table[++_tot].to=y;
    table[_tot].next=head[x];
    head[x]=_tot;
}
void DFS(int x)
{
    static int T;
    int i;
    dpt[x]=dpt[fa[x][0]]+1;
    st[x]=++T;
    for(i=head[x];i;i=table[i].next)
        if(table[i].to!=fa[x][0])
        {
            fa[table[i].to][0]=x;
            DFS(table[i].to);
        }
    ed[x]=T;
}
int LCA(int x,int y)
{
    int j;
    if(dpt[x]<dpt[y])
        swap(x,y);
    for(j=15;~j;j--)
        if(dpt[fa[x][j]]>=dpt[y])
            x=fa[x][j];
    if(x==y) return x;
    for(j=15;~j;j--)
        if(fa[x][j]!=fa[y][j])
            x=fa[x][j],y=fa[y][j];
    return fa[x][0];
}
int Second_LCA(int x,int y)
{
    int j;
    for(j=15;~j;j--)
        if(dpt[fa[y][j]]>dpt[x])
            y=fa[y][j];
    return y;
}
void Insert_Rectangle(int x1,int x2,int y1,int y2,int z)
{
    lines[++tot]=Line(1,x1,y1,y2,z);
    lines[++tot]=Line(-1,x2+1,y1,y2,z);
}
struct Segtree{
    Segtree *ls,*rs;
    int cnt;
    void* operator new (size_t)
    {
        static Segtree *mempool,*C;
        if(C==mempool)
            mempool=(C=new Segtree[1<<16])+(1<<16);
        C->ls=C->rs=0x0;
        C->cnt=0;
        return C++;
    }
    friend void Modify(Segtree *&p,int x,int y,int pos,int val)
    {
        int mid=x+y>>1;
        if(!p) p=new Segtree;
        p->cnt+=val;
        if(x==y)
            return ;
        if(pos<=mid)
            Modify(p->ls,x,mid,pos,val);
        else
            Modify(p->rs,mid+1,y,pos,val);
    }
    friend int Get_Kth(Segtree *stack[],int top,int x,int y,int k)
    {
        int i,mid=x+y>>1,cnt=0;
        if(x==y) return mid;
        for(i=1;i<=top;i++)
            cnt+=stack[i]&&stack[i]->ls?stack[i]->ls->cnt:0;
        if(k<=cnt)
        {
            for(i=1;i<=top;i++)
                stack[i]=stack[i]?stack[i]->ls:0x0;
            return Get_Kth(stack,top,x,mid,k);
        }
        else
        {
            for(i=1;i<=top;i++)
                stack[i]=stack[i]?stack[i]->rs:0x0;
            return Get_Kth(stack,top,mid+1,y,k-cnt);
        }
    }
};
namespace BIT{
    Segtree *c[M];
    void Update(int x,int pos,int val)
    {
        for(;x;x-=x&-x)
            Modify(c[x],0,1000000000,pos,val);
    }
    int Get_Kth(int x,int k)
    {
        static Segtree *stack[M];int top;
        top=0;
        for(;x<=n;x+=x&-x)
            stack[++top]=c[x];
        return Get_Kth(stack,top,0,1000000000,k);
    }
}
int main()
{
    using namespace BIT;
    int i,j,x,y,z;
    cin>>n>>m>>q;
    for(i=1;i<n;i++)
    {
        scanf("%d%d",&x,&y);
        Add(x,y);Add(y,x);
    }
    DFS(1);
    for(j=1;j<=15;j++)
        for(i=1;i<=n;i++)
            fa[i][j]=fa[fa[i][j-1]][j-1];
    for(i=1;i<=m;i++)
    {
        scanf("%d%d%d",&x,&y,&z);
        if(st[x]>st[y])
            swap(x,y);
        int lca=LCA(x,y);
        if(lca!=x)
            Insert_Rectangle(st[x],ed[x],st[y],ed[y],z);
        else
        {
            int temp=Second_LCA(x,y);
            if(st[temp]!=1)
                Insert_Rectangle(1,st[temp]-1,st[y],ed[y],z);
            if(ed[temp]!=n)
                Insert_Rectangle(st[y],ed[y],ed[temp]+1,n,z);
        }
    }
    sort(lines+1,lines+tot+1);
    for(i=1;i<=q;i++)
    {
        scanf("%d%d%d",&x,&y,&z);
        if(st[x]>st[y])
            swap(x,y);
        queries[i].x=st[x];
        queries[i].y=st[y];
        queries[i].k=z;
        queries[i].id=i;
    }
    sort(queries+1,queries+q+1);
    for(j=1,i=1;i<=q;i++)
    {

        for(;j<=tot&&lines[j].x<=queries[i].x;j++)
            Update(lines[j].y1-1,lines[j].z,-lines[j].type),
            Update(lines[j].y2,lines[j].z,lines[j].type);

        ans[queries[i].id]=Get_Kth(queries[i].y,queries[i].k);

    }
    for(i=1;i<=q;i++)
        printf("%d\n",ans[i]);
    return 0;
}
时间: 2024-10-15 02:58:13

BZOJ 4009 HNOI2015 接水果 树套树的相关文章

BZOJ 4009: [HNOI2015]接水果

4009: [HNOI2015]接水果 Time Limit: 60 Sec  Memory Limit: 512 MBSubmit: 636  Solved: 300[Submit][Status][Discuss] Description 风见幽香非常喜欢玩一个叫做 osu!的游戏,其中她最喜欢玩的模式就是接水果. 由于她已经DT FC 了The big black,  她觉得这个游戏太简单了,于是发明了一个更 加难的版本.首先有一个地图,是一棵由 n 个顶点.n-1 条边组成的树(例如图

bzoj 1901: Zju2112 Dynamic Rankings(树套树)

1901: Zju2112 Dynamic Rankings 经典的带修改求区间第k小值问题 树套树模板,我是用的线段树套splay实现的,而且用的数组模拟的,所以可能空间略大,bzoj过了,zoj过不了. 思路很简单,用线段树维护区间,用splay维护区间内的权值,然后询问的时候,二分答案key,然后在区间内找小于key的数有多少个. 贴上模板: #include<stdio.h> #include<string.h> #include<algorithm> #def

BZOJ 3196 二逼平衡树 树套树

题目大意:...BZOJ挂了自己看去 好吧既然BZOJ挂了我还是贴上来吧0.0 破服务器 维护一种数据结构,提供下列操作: 1.查询k在区间内的排名 2.查询区间内排名为k的值 3.修改某一位值上的数值 4.查询k在区间内的前驱(前驱定义为小于x,且最大的数) 5.查询k在区间内的后继(后继定义为大于x,且最小的数) 其实一开始觉得这题是划分树主席树之类的 然后去了解了一下发现完全写不了... 后来才知道原来是树套树 以前想过线段树套树状数组 这数据范围别说树套树了连树状数组都开不开 正解应该是

树套树专题——bzoj 3110: [Zjoi2013] K大数查询 &amp; 3236 [Ahoi2013] 作业 题解

[原题1] 3110: [Zjoi2013]K大数查询 Time Limit: 20 Sec  Memory Limit: 512 MB Submit: 978  Solved: 476 Description 有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c 如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数是多少. Input 第一行N,M 接下来M行,每行形如1 a b c或2 a b c Outpu

[BZOJ 3489] A simple rmq problem 【可持久化树套树】

题目链接:BZOJ - 3489 题目分析 “因为是OJ上的题,就简单点好了.”——出题人 真的..好..简单... 首先,我们求出每个数的前一个与它相同的数的位置,即 prev[i] ,如果前面没有相同的数,prev[i] = 0. 再求出每个数的后一个与它相同的数的位置,即 next[i], 如果后面没有相同的数,next[i] = n + 1. 这样,对于 l > prev[i], r < next[i] 的区间,i 这个数在区间中至多出现一次. 那么我们要求的就是:符合 prev[i]

BZOJ 3110: [Zjoi2013]K大数查询 [树套树]

3110: [Zjoi2013]K大数查询 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 6050  Solved: 2007[Submit][Status][Discuss] Description 有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数是多少. Input 第一行N,M接下来M行,每行形如1 a

bzoj 3295: [Cqoi2011]动态逆序对(树套树 or CDQ分治)

Description 对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数.给1到n的一个排列,按照某种顺序依次删除m个元素,你的任务是在每次删除一个元素之前统计整个序列的逆序对数. Input 输入第一行包含两个整数n和m,即初始元素的个数和删除的元素个数.以下n行每行包含一个1到n之间的正整数,即初始排列.以下m行每行一个正整数,依次为每次删除的元素. Output 输出包含m行,依次为删除每个元素之前,逆序对的个数. Sample Input 5 4 1 5 3

BZOJ 2141 排队 树套树

题目大意:给出一个数列,支持交换两个数字的操作,问每次操作之后的逆序对数量. 思路:数字比较大,先离散化.然后先求一次总逆序对,每次交换两个数字的时候用树套树维护一下逆序对的总数就可以了.. 好像树套树的常数略大,正解应该是分块.. CODE: #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define MAX 20010 using namesp

BZOJ 3196 二逼平衡树 树套树(线段树套Treap)

题目大意: 写一种数据结构,他可以: 1.查询k在区间内的排名. 2.查询区间内排名为k的值 3.修改某一个值. 4.求k在区间内的前驱. 5.求k在区间内的后继. 思路:本来以为有什么只有神犇才知道的神一般的数据结构来维护它,问了别人之后,发现只是树套树.据说怎么套都行.我见识鄙陋,就只能线段树套Treap了. 这也是第一次写树套树,还1A了,有点开心. 写树套树,一定要确定自己对这两个树及其熟练,加上少量精细的思考,就可以完成树套树.(我只是弱渣,求神犇别D) 具体实现:第一层是线段树,第二